{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<h1 align=\"center\"> Facebook Data ROI </h1>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A lot of original text came from https://www.kaggle.com/chrisbow/an-introduction-to-facebook-ad-analysis-using-r"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "%matplotlib inline"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Load Dataset \n",
    "#### About Data Columns"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "1.) ad_id: an unique ID for each ad. <br>\n",
    "2.) xyz_campaign_id: an ID associated with each ad campaign of XYZ company. <br>\n",
    "3.) fb_campaign_id: an ID associated with how Facebook tracks each campaign. <br>\n",
    "4.) age: age of the person to whom the ad is shown. <br>\n",
    "5.) gender: gender of the person to whim the add is shown <br>\n",
    "6.) interest: a code specifying the category to which the person's interest belongs (interests are as mentioned in the person's Facebook public profile). <br>\n",
    "7.) Impressions: the number of times the ad was shown. <br>\n",
    "8.) Clicks: number of clicks on for that ad. <br>\n",
    "9.) Spent: Amount paid by company xyz to Facebook, to show that ad. <br>\n",
    "10.) Total conversion: Total number of people who enquired about the product after seeing the ad. <br>\n",
    "11.) Approved conversion: Total number of people who bought the product after seeing the ad."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Load the Data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "url = 'https://raw.githubusercontent.com/mGalarnyk/Python_Tutorials/master/Kaggle/Facebook/KAG_conversion_data.csv'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Load dataset into Pandas DataFrame\n",
    "df = pd.read_csv(url)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Exploratory Data Analysis"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1178    625\n",
       "936     464\n",
       "916      54\n",
       "Name: xyz_campaign_id, dtype: int64"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df.xyz_campaign_id.value_counts(dropna=False)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "xyz_campaign_id\n",
       "916        482925\n",
       "936       8128187\n",
       "1178    204823716\n",
       "Name: Impressions, dtype: int64"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df.groupby(['xyz_campaign_id']).Impressions.sum()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "30-34    426\n",
       "45-49    259\n",
       "35-39    248\n",
       "40-44    210\n",
       "Name: age, dtype: int64"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df.age.value_counts(dropna=False)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Look at Gender"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [],
   "source": [
    "uniqueCampaigns = df.xyz_campaign_id.unique()\n",
    "df_1 = df[df.xyz_campaign_id == uniqueCampaigns[0] ]\n",
    "df_2 = df[df.xyz_campaign_id == uniqueCampaigns[1] ]\n",
    "df_3 = df[df.xyz_campaign_id == uniqueCampaigns[2] ]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 221,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th>Impressions</th>\n",
       "      <th>Clicks</th>\n",
       "      <th>Spent</th>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>gender</th>\n",
       "      <th>age</th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th rowspan=\"4\" valign=\"top\">F</th>\n",
       "      <th>30-34</th>\n",
       "      <td>151603</td>\n",
       "      <td>36</td>\n",
       "      <td>47.99</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>35-39</th>\n",
       "      <td>11155</td>\n",
       "      <td>4</td>\n",
       "      <td>5.62</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>40-44</th>\n",
       "      <td>3812</td>\n",
       "      <td>1</td>\n",
       "      <td>1.13</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>45-49</th>\n",
       "      <td>30511</td>\n",
       "      <td>11</td>\n",
       "      <td>15.11</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th rowspan=\"4\" valign=\"top\">M</th>\n",
       "      <th>30-34</th>\n",
       "      <td>106069</td>\n",
       "      <td>21</td>\n",
       "      <td>27.34</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>35-39</th>\n",
       "      <td>69921</td>\n",
       "      <td>13</td>\n",
       "      <td>18.02</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>40-44</th>\n",
       "      <td>58165</td>\n",
       "      <td>13</td>\n",
       "      <td>15.68</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>45-49</th>\n",
       "      <td>51689</td>\n",
       "      <td>14</td>\n",
       "      <td>18.82</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "              Impressions  Clicks  Spent\n",
       "gender age                              \n",
       "F      30-34       151603      36  47.99\n",
       "       35-39        11155       4   5.62\n",
       "       40-44         3812       1   1.13\n",
       "       45-49        30511      11  15.11\n",
       "M      30-34       106069      21  27.34\n",
       "       35-39        69921      13  18.02\n",
       "       40-44        58165      13  15.68\n",
       "       45-49        51689      14  18.82"
      ]
     },
     "execution_count": 221,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df_1.groupby(['gender', 'age']).agg({'Impressions': sum, 'Clicks': sum, 'Spent': sum})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 129,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>ad_id</th>\n",
       "      <th>xyz_campaign_id</th>\n",
       "      <th>fb_campaign_id</th>\n",
       "      <th>age</th>\n",
       "      <th>gender</th>\n",
       "      <th>interest</th>\n",
       "      <th>Impressions</th>\n",
       "      <th>Clicks</th>\n",
       "      <th>Spent</th>\n",
       "      <th>Total_Conversion</th>\n",
       "      <th>Approved_Conversion</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>708746</td>\n",
       "      <td>916</td>\n",
       "      <td>103916</td>\n",
       "      <td>30-34</td>\n",
       "      <td>M</td>\n",
       "      <td>15</td>\n",
       "      <td>7350</td>\n",
       "      <td>1</td>\n",
       "      <td>1.43</td>\n",
       "      <td>2</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>708749</td>\n",
       "      <td>916</td>\n",
       "      <td>103917</td>\n",
       "      <td>30-34</td>\n",
       "      <td>M</td>\n",
       "      <td>16</td>\n",
       "      <td>17861</td>\n",
       "      <td>2</td>\n",
       "      <td>1.82</td>\n",
       "      <td>2</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>708771</td>\n",
       "      <td>916</td>\n",
       "      <td>103920</td>\n",
       "      <td>30-34</td>\n",
       "      <td>M</td>\n",
       "      <td>20</td>\n",
       "      <td>693</td>\n",
       "      <td>0</td>\n",
       "      <td>0.00</td>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>708815</td>\n",
       "      <td>916</td>\n",
       "      <td>103928</td>\n",
       "      <td>30-34</td>\n",
       "      <td>M</td>\n",
       "      <td>28</td>\n",
       "      <td>4259</td>\n",
       "      <td>1</td>\n",
       "      <td>1.25</td>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>708818</td>\n",
       "      <td>916</td>\n",
       "      <td>103928</td>\n",
       "      <td>30-34</td>\n",
       "      <td>M</td>\n",
       "      <td>28</td>\n",
       "      <td>4133</td>\n",
       "      <td>1</td>\n",
       "      <td>1.29</td>\n",
       "      <td>1</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "    ad_id  xyz_campaign_id  fb_campaign_id    age gender  interest  \\\n",
       "0  708746              916          103916  30-34      M        15   \n",
       "1  708749              916          103917  30-34      M        16   \n",
       "2  708771              916          103920  30-34      M        20   \n",
       "3  708815              916          103928  30-34      M        28   \n",
       "4  708818              916          103928  30-34      M        28   \n",
       "\n",
       "   Impressions  Clicks  Spent  Total_Conversion  Approved_Conversion  \n",
       "0         7350       1   1.43                 2                    1  \n",
       "1        17861       2   1.82                 2                    0  \n",
       "2          693       0   0.00                 1                    0  \n",
       "3         4259       1   1.25                 1                    0  \n",
       "4         4133       1   1.29                 1                    1  "
      ]
     },
     "execution_count": 129,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df_1.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 213,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Number of rows in the groupby\n",
    "temp_df = pd.DataFrame(df_1.groupby(['gender', 'age']).size(), columns = ['counts'])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 214,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th>counts</th>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>gender</th>\n",
       "      <th>age</th>\n",
       "      <th></th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th rowspan=\"4\" valign=\"top\">F</th>\n",
       "      <th>30-34</th>\n",
       "      <td>11</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>35-39</th>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>40-44</th>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>45-49</th>\n",
       "      <td>4</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th rowspan=\"4\" valign=\"top\">M</th>\n",
       "      <th>30-34</th>\n",
       "      <td>18</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>35-39</th>\n",
       "      <td>9</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>40-44</th>\n",
       "      <td>5</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>45-49</th>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "              counts\n",
       "gender age          \n",
       "F      30-34      11\n",
       "       35-39       3\n",
       "       40-44       1\n",
       "       45-49       4\n",
       "M      30-34      18\n",
       "       35-39       9\n",
       "       40-44       5\n",
       "       45-49       3"
      ]
     },
     "execution_count": 214,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "temp_df"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 215,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead tr th {\n",
       "        text-align: left;\n",
       "    }\n",
       "\n",
       "    .dataframe thead tr:last-of-type th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr>\n",
       "      <th></th>\n",
       "      <th colspan=\"4\" halign=\"left\">counts</th>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>age</th>\n",
       "      <th>30-34</th>\n",
       "      <th>35-39</th>\n",
       "      <th>40-44</th>\n",
       "      <th>45-49</th>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>gender</th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>F</th>\n",
       "      <td>11</td>\n",
       "      <td>3</td>\n",
       "      <td>1</td>\n",
       "      <td>4</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>M</th>\n",
       "      <td>18</td>\n",
       "      <td>9</td>\n",
       "      <td>5</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "       counts                  \n",
       "age     30-34 35-39 40-44 45-49\n",
       "gender                         \n",
       "F          11     3     1     4\n",
       "M          18     9     5     3"
      ]
     },
     "execution_count": 215,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "temp_df.unstack(level = 'age')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 216,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead tr th {\n",
       "        text-align: left;\n",
       "    }\n",
       "\n",
       "    .dataframe thead tr:last-of-type th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr>\n",
       "      <th></th>\n",
       "      <th colspan=\"4\" halign=\"left\">counts</th>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>age</th>\n",
       "      <th>30-34</th>\n",
       "      <th>35-39</th>\n",
       "      <th>40-44</th>\n",
       "      <th>45-49</th>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>gender</th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>F</th>\n",
       "      <td>11</td>\n",
       "      <td>3</td>\n",
       "      <td>1</td>\n",
       "      <td>4</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>M</th>\n",
       "      <td>18</td>\n",
       "      <td>9</td>\n",
       "      <td>5</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "       counts                  \n",
       "age     30-34 35-39 40-44 45-49\n",
       "gender                         \n",
       "F          11     3     1     4\n",
       "M          18     9     5     3"
      ]
     },
     "execution_count": 216,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "temp_df.unstack()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 217,
   "metadata": {},
   "outputs": [],
   "source": [
    "to_graph_df = temp_df.unstack(level = 'age')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 209,
   "metadata": {},
   "outputs": [],
   "source": [
    "to_graph_df.columns = to_graph_df.columns.droplevel(0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 211,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th>age</th>\n",
       "      <th>30-34</th>\n",
       "      <th>35-39</th>\n",
       "      <th>40-44</th>\n",
       "      <th>45-49</th>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>gender</th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>F</th>\n",
       "      <td>11</td>\n",
       "      <td>3</td>\n",
       "      <td>1</td>\n",
       "      <td>4</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>M</th>\n",
       "      <td>18</td>\n",
       "      <td>9</td>\n",
       "      <td>5</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "age     30-34  35-39  40-44  45-49\n",
       "gender                            \n",
       "F          11      3      1      4\n",
       "M          18      9      5      3"
      ]
     },
     "execution_count": 211,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "to_graph_df"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 212,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "ax = to_graph_df.plot.bar(yticks = range(0, 21,1), rot = 0);\n",
    "ax.grid(True, axis = 'y', alpha = .3);\n",
    "ax.legend();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": 126,
   "metadata": {},
   "outputs": [],
   "source": [
    "temp_df.unstack?"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Figure Before and After"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 101,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th>age</th>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>gender</th>\n",
       "      <th>age</th>\n",
       "      <th></th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th rowspan=\"4\" valign=\"top\">F</th>\n",
       "      <th>30-34</th>\n",
       "      <td>11</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>35-39</th>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>40-44</th>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>45-49</th>\n",
       "      <td>4</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th rowspan=\"4\" valign=\"top\">M</th>\n",
       "      <th>30-34</th>\n",
       "      <td>18</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>35-39</th>\n",
       "      <td>9</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>40-44</th>\n",
       "      <td>5</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>45-49</th>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "              age\n",
       "gender age       \n",
       "F      30-34   11\n",
       "       35-39    3\n",
       "       40-44    1\n",
       "       45-49    4\n",
       "M      30-34   18\n",
       "       35-39    9\n",
       "       40-44    5\n",
       "       45-49    3"
      ]
     },
     "execution_count": 101,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Before\n",
    "temp_df"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 94,
   "metadata": {},
   "outputs": [],
   "source": [
    "# After, bar graph. \n",
    "temp_df.unstack?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 96,
   "metadata": {},
   "outputs": [
    {
     "ename": "ValueError",
     "evalue": "cannot insert age, already exists",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m-----------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mValueError\u001b[0m                            Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-96-6414c066ee68>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mtemp_df\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mreset_index\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mlevel\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m'age'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[0;32m~/anaconda3/lib/python3.6/site-packages/pandas/core/frame.py\u001b[0m in \u001b[0;36mreset_index\u001b[0;34m(self, level, drop, inplace, col_level, col_fill)\u001b[0m\n\u001b[1;32m   3377\u001b[0m                 \u001b[0;31m# to ndarray and maybe infer different dtype\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m   3378\u001b[0m                 \u001b[0mlevel_values\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0m_maybe_casted_values\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mlev\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlab\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 3379\u001b[0;31m                 \u001b[0mnew_obj\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0minsert\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mname\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlevel_values\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m   3380\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m   3381\u001b[0m         \u001b[0mnew_obj\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mindex\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnew_index\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m~/anaconda3/lib/python3.6/site-packages/pandas/core/frame.py\u001b[0m in \u001b[0;36minsert\u001b[0;34m(self, loc, column, value, allow_duplicates)\u001b[0m\n\u001b[1;32m   2611\u001b[0m         \u001b[0mvalue\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_sanitize_column\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcolumn\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mvalue\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mbroadcast\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mFalse\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m   2612\u001b[0m         self._data.insert(loc, column, value,\n\u001b[0;32m-> 2613\u001b[0;31m                           allow_duplicates=allow_duplicates)\n\u001b[0m\u001b[1;32m   2614\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m   2615\u001b[0m     \u001b[0;32mdef\u001b[0m \u001b[0massign\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m~/anaconda3/lib/python3.6/site-packages/pandas/core/internals.py\u001b[0m in \u001b[0;36minsert\u001b[0;34m(self, loc, item, value, allow_duplicates)\u001b[0m\n\u001b[1;32m   4061\u001b[0m         \u001b[0;32mif\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mallow_duplicates\u001b[0m \u001b[0;32mand\u001b[0m \u001b[0mitem\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mitems\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m   4062\u001b[0m             \u001b[0;31m# Should this be a different kind of error??\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 4063\u001b[0;31m             \u001b[0;32mraise\u001b[0m \u001b[0mValueError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'cannot insert {}, already exists'\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mformat\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mitem\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m   4064\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m   4065\u001b[0m         \u001b[0;32mif\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mloc\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mint\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;31mValueError\u001b[0m: cannot insert age, already exists"
     ]
    }
   ],
   "source": [
    "temp_df.reset_index(level = 'age')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 80,
   "metadata": {},
   "outputs": [
    {
     "ename": "ValueError",
     "evalue": "cannot label index with a null key",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m-----------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mValueError\u001b[0m                            Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-80-febcde5ce7fb>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mtemp_df\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpivot\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mindex\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m'age'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[0;32m~/anaconda3/lib/python3.6/site-packages/pandas/core/frame.py\u001b[0m in \u001b[0;36mpivot\u001b[0;34m(self, index, columns, values)\u001b[0m\n\u001b[1;32m   4380\u001b[0m         \"\"\"\n\u001b[1;32m   4381\u001b[0m         \u001b[0;32mfrom\u001b[0m \u001b[0mpandas\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcore\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mreshape\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mreshape\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mpivot\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 4382\u001b[0;31m         \u001b[0;32mreturn\u001b[0m \u001b[0mpivot\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mindex\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mindex\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcolumns\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mcolumns\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mvalues\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mvalues\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m   4383\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m   4384\u001b[0m     _shared_docs['pivot_table'] = \"\"\"\n",
      "\u001b[0;32m~/anaconda3/lib/python3.6/site-packages/pandas/core/reshape/reshape.py\u001b[0m in \u001b[0;36mpivot\u001b[0;34m(self, index, columns, values)\u001b[0m\n\u001b[1;32m    378\u001b[0m         \u001b[0mcols\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0mcolumns\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mindex\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0;32mNone\u001b[0m \u001b[0;32melse\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0mindex\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcolumns\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    379\u001b[0m         \u001b[0mappend\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mindex\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 380\u001b[0;31m         \u001b[0mindexed\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mset_index\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcols\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mappend\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mappend\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    381\u001b[0m         \u001b[0;32mreturn\u001b[0m \u001b[0mindexed\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0munstack\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcolumns\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    382\u001b[0m     \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m~/anaconda3/lib/python3.6/site-packages/pandas/core/frame.py\u001b[0m in \u001b[0;36mset_index\u001b[0;34m(self, keys, drop, append, inplace, verify_integrity)\u001b[0m\n\u001b[1;32m   3144\u001b[0m                 \u001b[0mnames\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mappend\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;32mNone\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m   3145\u001b[0m             \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 3146\u001b[0;31m                 \u001b[0mlevel\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mframe\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mcol\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_values\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m   3147\u001b[0m                 \u001b[0mnames\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mappend\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcol\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m   3148\u001b[0m                 \u001b[0;32mif\u001b[0m \u001b[0mdrop\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m~/anaconda3/lib/python3.6/site-packages/pandas/core/frame.py\u001b[0m in \u001b[0;36m__getitem__\u001b[0;34m(self, key)\u001b[0m\n\u001b[1;32m   2137\u001b[0m             \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_getitem_multilevel\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mkey\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m   2138\u001b[0m         \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 2139\u001b[0;31m             \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_getitem_column\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mkey\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m   2140\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m   2141\u001b[0m     \u001b[0;32mdef\u001b[0m \u001b[0m_getitem_column\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mkey\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m~/anaconda3/lib/python3.6/site-packages/pandas/core/frame.py\u001b[0m in \u001b[0;36m_getitem_column\u001b[0;34m(self, key)\u001b[0m\n\u001b[1;32m   2144\u001b[0m         \u001b[0;31m# get column\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m   2145\u001b[0m         \u001b[0;32mif\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcolumns\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mis_unique\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 2146\u001b[0;31m             \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_get_item_cache\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mkey\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m   2147\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m   2148\u001b[0m         \u001b[0;31m# duplicate columns & possible reduce dimensionality\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m~/anaconda3/lib/python3.6/site-packages/pandas/core/generic.py\u001b[0m in \u001b[0;36m_get_item_cache\u001b[0;34m(self, item)\u001b[0m\n\u001b[1;32m   1840\u001b[0m         \u001b[0mres\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcache\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mitem\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m   1841\u001b[0m         \u001b[0;32mif\u001b[0m \u001b[0mres\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1842\u001b[0;31m             \u001b[0mvalues\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_data\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mitem\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m   1843\u001b[0m             \u001b[0mres\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_box_item_values\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mitem\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mvalues\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m   1844\u001b[0m             \u001b[0mcache\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mitem\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mres\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m~/anaconda3/lib/python3.6/site-packages/pandas/core/internals.py\u001b[0m in \u001b[0;36mget\u001b[0;34m(self, item, fastpath)\u001b[0m\n\u001b[1;32m   3850\u001b[0m                         \u001b[0mloc\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mindexer\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mitem\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m   3851\u001b[0m                     \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 3852\u001b[0;31m                         \u001b[0;32mraise\u001b[0m \u001b[0mValueError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"cannot label index with a null key\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m   3853\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m   3854\u001b[0m             \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0miget\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mloc\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mfastpath\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mfastpath\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;31mValueError\u001b[0m: cannot label index with a null key"
     ]
    }
   ],
   "source": [
    "temp_df.pivot(index = 'age')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 77,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\"\"\"\r\n",
      "DataFrame\r\n",
      "---------\r\n",
      "An efficient 2D container for potentially mixed-type time series or other\r\n",
      "labeled data series.\r\n",
      "\r\n",
      "Similar to its R counterpart, data.frame, except providing automatic data\r\n",
      "alignment and a host of useful data manipulation methods having to do with the\r\n",
      "labeling information\r\n",
      "\"\"\"\r\n",
      "from __future__ import division\r\n",
      "# pylint: disable=E1101,E1103\r\n",
      "# pylint: disable=W0212,W0231,W0703,W0622\r\n",
      "\r\n",
      "import functools\r\n",
      "import collections\r\n",
      "import itertools\r\n",
      "import sys\r\n",
      "import types\r\n",
      "import warnings\r\n",
      "from textwrap import dedent\r\n",
      "\r\n",
      "import numpy as np\r\n",
      "import numpy.ma as ma\r\n",
      "\r\n",
      "from pandas.core.dtypes.cast import (\r\n",
      "    maybe_upcast,\r\n",
      "    cast_scalar_to_array,\r\n",
      "    maybe_cast_to_datetime,\r\n",
      "    maybe_infer_to_datetimelike,\r\n",
      "    maybe_convert_platform,\r\n",
      "    maybe_downcast_to_dtype,\r\n",
      "    invalidate_string_dtypes,\r\n",
      "    coerce_to_dtypes,\r\n",
      "    maybe_upcast_putmask,\r\n",
      "    find_common_type)\r\n",
      "from pandas.core.dtypes.common import (\r\n",
      "    is_categorical_dtype,\r\n",
      "    is_object_dtype,\r\n",
      "    is_extension_type,\r\n",
      "    is_datetimetz,\r\n",
      "    is_datetime64_any_dtype,\r\n",
      "    is_datetime64tz_dtype,\r\n",
      "    is_bool_dtype,\r\n",
      "    is_integer_dtype,\r\n",
      "    is_float_dtype,\r\n",
      "    is_integer,\r\n",
      "    is_scalar,\r\n",
      "    is_dtype_equal,\r\n",
      "    needs_i8_conversion,\r\n",
      "    _get_dtype_from_object,\r\n",
      "    _ensure_float,\r\n",
      "    _ensure_float64,\r\n",
      "    _ensure_int64,\r\n",
      "    _ensure_platform_int,\r\n",
      "    is_list_like,\r\n",
      "    is_iterator,\r\n",
      "    is_sequence,\r\n",
      "    is_named_tuple)\r\n",
      "from pandas.core.dtypes.missing import isna, notna\r\n",
      "\r\n",
      "\r\n",
      "from pandas.core.common import (_try_sort,\r\n",
      "                                _default_index,\r\n",
      "                                _values_from_object,\r\n",
      "                                _maybe_box_datetimelike,\r\n",
      "                                _dict_compat,\r\n",
      "                                standardize_mapping)\r\n",
      "from pandas.core.generic import NDFrame, _shared_docs\r\n",
      "from pandas.core.index import (Index, MultiIndex, _ensure_index,\r\n",
      "                               _ensure_index_from_sequences)\r\n",
      "from pandas.core.indexing import (maybe_droplevels, convert_to_index_sliceable,\r\n",
      "                                  check_bool_indexer)\r\n",
      "from pandas.core.internals import (BlockManager,\r\n",
      "                                   create_block_manager_from_arrays,\r\n",
      "                                   create_block_manager_from_blocks)\r\n",
      "from pandas.core.series import Series\r\n",
      "from pandas.core.categorical import Categorical\r\n",
      "import pandas.core.algorithms as algorithms\r\n",
      "from pandas.compat import (range, map, zip, lrange, lmap, lzip, StringIO, u,\r\n",
      "                           OrderedDict, raise_with_traceback)\r\n",
      "from pandas import compat\r\n",
      "from pandas.compat import PY36\r\n",
      "from pandas.compat.numpy import function as nv\r\n",
      "from pandas.util._decorators import (Appender, Substitution,\r\n",
      "                                     rewrite_axis_style_signature)\r\n",
      "from pandas.util._validators import (validate_bool_kwarg,\r\n",
      "                                     validate_axis_style_args)\r\n",
      "\r\n",
      "from pandas.core.indexes.period import PeriodIndex\r\n",
      "from pandas.core.indexes.datetimes import DatetimeIndex\r\n",
      "from pandas.core.indexes.timedeltas import TimedeltaIndex\r\n",
      "\r\n",
      "from pandas.core import accessor\r\n",
      "import pandas.core.common as com\r\n",
      "import pandas.core.nanops as nanops\r\n",
      "import pandas.core.ops as ops\r\n",
      "import pandas.io.formats.format as fmt\r\n",
      "import pandas.io.formats.console as console\r\n",
      "from pandas.io.formats.printing import pprint_thing\r\n",
      "import pandas.plotting._core as gfx\r\n",
      "\r\n",
      "from pandas._libs import lib, algos as libalgos\r\n",
      "\r\n",
      "from pandas.core.config import get_option\r\n",
      "\r\n",
      "# ---------------------------------------------------------------------\r\n",
      "# Docstring templates\r\n",
      "\r\n",
      "_shared_doc_kwargs = dict(\r\n",
      "    axes='index, columns', klass='DataFrame',\r\n",
      "    axes_single_arg=\"{0 or 'index', 1 or 'columns'}\",\r\n",
      "    optional_by=\"\"\"\r\n",
      "        by : str or list of str\r\n",
      "            Name or list of names which refer to the axis items.\"\"\",\r\n",
      "    versionadded_to_excel='',\r\n",
      "    optional_labels=\"\"\"labels : array-like, optional\r\n",
      "            New labels / index to conform the axis specified by 'axis' to.\"\"\",\r\n",
      "    optional_axis=\"\"\"axis : int or str, optional\r\n",
      "            Axis to target. Can be either the axis name ('index', 'columns')\r\n",
      "            or number (0, 1).\"\"\",\r\n",
      ")\r\n",
      "\r\n",
      "_numeric_only_doc = \"\"\"numeric_only : boolean, default None\r\n",
      "    Include only float, int, boolean data. If None, will attempt to use\r\n",
      "    everything, then use only numeric data\r\n",
      "\"\"\"\r\n",
      "\r\n",
      "_merge_doc = \"\"\"\r\n",
      "Merge DataFrame objects by performing a database-style join operation by\r\n",
      "columns or indexes.\r\n",
      "\r\n",
      "If joining columns on columns, the DataFrame indexes *will be\r\n",
      "ignored*. Otherwise if joining indexes on indexes or indexes on a column or\r\n",
      "columns, the index will be passed on.\r\n",
      "\r\n",
      "Parameters\r\n",
      "----------%s\r\n",
      "right : DataFrame\r\n",
      "how : {'left', 'right', 'outer', 'inner'}, default 'inner'\r\n",
      "    * left: use only keys from left frame, similar to a SQL left outer join;\r\n",
      "      preserve key order\r\n",
      "    * right: use only keys from right frame, similar to a SQL right outer join;\r\n",
      "      preserve key order\r\n",
      "    * outer: use union of keys from both frames, similar to a SQL full outer\r\n",
      "      join; sort keys lexicographically\r\n",
      "    * inner: use intersection of keys from both frames, similar to a SQL inner\r\n",
      "      join; preserve the order of the left keys\r\n",
      "on : label or list\r\n",
      "    Field names to join on. Must be found in both DataFrames. If on is\r\n",
      "    None and not merging on indexes, then it merges on the intersection of\r\n",
      "    the columns by default.\r\n",
      "left_on : label or list, or array-like\r\n",
      "    Field names to join on in left DataFrame. Can be a vector or list of\r\n",
      "    vectors of the length of the DataFrame to use a particular vector as\r\n",
      "    the join key instead of columns\r\n",
      "right_on : label or list, or array-like\r\n",
      "    Field names to join on in right DataFrame or vector/list of vectors per\r\n",
      "    left_on docs\r\n",
      "left_index : boolean, default False\r\n",
      "    Use the index from the left DataFrame as the join key(s). If it is a\r\n",
      "    MultiIndex, the number of keys in the other DataFrame (either the index\r\n",
      "    or a number of columns) must match the number of levels\r\n",
      "right_index : boolean, default False\r\n",
      "    Use the index from the right DataFrame as the join key. Same caveats as\r\n",
      "    left_index\r\n",
      "sort : boolean, default False\r\n",
      "    Sort the join keys lexicographically in the result DataFrame. If False,\r\n",
      "    the order of the join keys depends on the join type (how keyword)\r\n",
      "suffixes : 2-length sequence (tuple, list, ...)\r\n",
      "    Suffix to apply to overlapping column names in the left and right\r\n",
      "    side, respectively\r\n",
      "copy : boolean, default True\r\n",
      "    If False, do not copy data unnecessarily\r\n",
      "indicator : boolean or string, default False\r\n",
      "    If True, adds a column to output DataFrame called \"_merge\" with\r\n",
      "    information on the source of each row.\r\n",
      "    If string, column with information on source of each row will be added to\r\n",
      "    output DataFrame, and column will be named value of string.\r\n",
      "    Information column is Categorical-type and takes on a value of \"left_only\"\r\n",
      "    for observations whose merge key only appears in 'left' DataFrame,\r\n",
      "    \"right_only\" for observations whose merge key only appears in 'right'\r\n",
      "    DataFrame, and \"both\" if the observation's merge key is found in both.\r\n",
      "\r\n",
      "    .. versionadded:: 0.17.0\r\n",
      "\r\n",
      "validate : string, default None\r\n",
      "    If specified, checks if merge is of specified type.\r\n",
      "\r\n",
      "    * \"one_to_one\" or \"1:1\": check if merge keys are unique in both\r\n",
      "      left and right datasets.\r\n",
      "    * \"one_to_many\" or \"1:m\": check if merge keys are unique in left\r\n",
      "      dataset.\r\n",
      "    * \"many_to_one\" or \"m:1\": check if merge keys are unique in right\r\n",
      "      dataset.\r\n",
      "    * \"many_to_many\" or \"m:m\": allowed, but does not result in checks.\r\n",
      "\r\n",
      "    .. versionadded:: 0.21.0\r\n",
      "\r\n",
      "Examples\r\n",
      "--------\r\n",
      "\r\n",
      ">>> A              >>> B\r\n",
      "    lkey value         rkey value\r\n",
      "0   foo  1         0   foo  5\r\n",
      "1   bar  2         1   bar  6\r\n",
      "2   baz  3         2   qux  7\r\n",
      "3   foo  4         3   bar  8\r\n",
      "\r\n",
      ">>> A.merge(B, left_on='lkey', right_on='rkey', how='outer')\r\n",
      "   lkey  value_x  rkey  value_y\r\n",
      "0  foo   1        foo   5\r\n",
      "1  foo   4        foo   5\r\n",
      "2  bar   2        bar   6\r\n",
      "3  bar   2        bar   8\r\n",
      "4  baz   3        NaN   NaN\r\n",
      "5  NaN   NaN      qux   7\r\n",
      "\r\n",
      "Returns\r\n",
      "-------\r\n",
      "merged : DataFrame\r\n",
      "    The output type will the be same as 'left', if it is a subclass\r\n",
      "    of DataFrame.\r\n",
      "\r\n",
      "See also\r\n",
      "--------\r\n",
      "merge_ordered\r\n",
      "merge_asof\r\n",
      "\r\n",
      "\"\"\"\r\n",
      "\r\n",
      "# -----------------------------------------------------------------------\r\n",
      "# DataFrame class\r\n",
      "\r\n",
      "\r\n",
      "class DataFrame(NDFrame):\r\n",
      "    \"\"\" Two-dimensional size-mutable, potentially heterogeneous tabular data\r\n",
      "    structure with labeled axes (rows and columns). Arithmetic operations\r\n",
      "    align on both row and column labels. Can be thought of as a dict-like\r\n",
      "    container for Series objects. The primary pandas data structure\r\n",
      "\r\n",
      "    Parameters\r\n",
      "    ----------\r\n",
      "    data : numpy ndarray (structured or homogeneous), dict, or DataFrame\r\n",
      "        Dict can contain Series, arrays, constants, or list-like objects\r\n",
      "    index : Index or array-like\r\n",
      "        Index to use for resulting frame. Will default to np.arange(n) if\r\n",
      "        no indexing information part of input data and no index provided\r\n",
      "    columns : Index or array-like\r\n",
      "        Column labels to use for resulting frame. Will default to\r\n",
      "        np.arange(n) if no column labels are provided\r\n",
      "    dtype : dtype, default None\r\n",
      "        Data type to force. Only a single dtype is allowed. If None, infer\r\n",
      "    copy : boolean, default False\r\n",
      "        Copy data from inputs. Only affects DataFrame / 2d ndarray input\r\n",
      "\r\n",
      "    Examples\r\n",
      "    --------\r\n",
      "    Constructing DataFrame from a dictionary.\r\n",
      "\r\n",
      "    >>> d = {'col1': [1, 2], 'col2': [3, 4]}\r\n",
      "    >>> df = pd.DataFrame(data=d)\r\n",
      "    >>> df\r\n",
      "       col1  col2\r\n",
      "    0     1     3\r\n",
      "    1     2     4\r\n",
      "\r\n",
      "    Notice that the inferred dtype is int64.\r\n",
      "\r\n",
      "    >>> df.dtypes\r\n",
      "    col1    int64\r\n",
      "    col2    int64\r\n",
      "    dtype: object\r\n",
      "\r\n",
      "    To enforce a single dtype:\r\n",
      "\r\n",
      "    >>> df = pd.DataFrame(data=d, dtype=np.int8)\r\n",
      "    >>> df.dtypes\r\n",
      "    col1    int8\r\n",
      "    col2    int8\r\n",
      "    dtype: object\r\n",
      "\r\n",
      "    Constructing DataFrame from numpy ndarray:\r\n",
      "\r\n",
      "    >>> df2 = pd.DataFrame(np.random.randint(low=0, high=10, size=(5, 5)),\r\n",
      "    ...                    columns=['a', 'b', 'c', 'd', 'e'])\r\n",
      "    >>> df2\r\n",
      "        a   b   c   d   e\r\n",
      "    0   2   8   8   3   4\r\n",
      "    1   4   2   9   0   9\r\n",
      "    2   1   0   7   8   0\r\n",
      "    3   5   1   7   1   3\r\n",
      "    4   6   0   2   4   2\r\n",
      "\r\n",
      "    See also\r\n",
      "    --------\r\n",
      "    DataFrame.from_records : constructor from tuples, also record arrays\r\n",
      "    DataFrame.from_dict : from dicts of Series, arrays, or dicts\r\n",
      "    DataFrame.from_items : from sequence of (key, value) pairs\r\n",
      "    pandas.read_csv, pandas.read_table, pandas.read_clipboard\r\n",
      "    \"\"\"\r\n",
      "\r\n",
      "    @property\r\n",
      "    def _constructor(self):\r\n",
      "        return DataFrame\r\n",
      "\r\n",
      "    _constructor_sliced = Series\r\n",
      "    _deprecations = NDFrame._deprecations | frozenset(\r\n",
      "        ['sortlevel', 'get_value', 'set_value', 'from_csv'])\r\n",
      "\r\n",
      "    @property\r\n",
      "    def _constructor_expanddim(self):\r\n",
      "        from pandas.core.panel import Panel\r\n",
      "        return Panel\r\n",
      "\r\n",
      "    def __init__(self, data=None, index=None, columns=None, dtype=None,\r\n",
      "                 copy=False):\r\n",
      "        if data is None:\r\n",
      "            data = {}\r\n",
      "        if dtype is not None:\r\n",
      "            dtype = self._validate_dtype(dtype)\r\n",
      "\r\n",
      "        if isinstance(data, DataFrame):\r\n",
      "            data = data._data\r\n",
      "\r\n",
      "        if isinstance(data, BlockManager):\r\n",
      "            mgr = self._init_mgr(data, axes=dict(index=index, columns=columns),\r\n",
      "                                 dtype=dtype, copy=copy)\r\n",
      "        elif isinstance(data, dict):\r\n",
      "            mgr = self._init_dict(data, index, columns, dtype=dtype)\r\n",
      "        elif isinstance(data, ma.MaskedArray):\r\n",
      "            import numpy.ma.mrecords as mrecords\r\n",
      "            # masked recarray\r\n",
      "            if isinstance(data, mrecords.MaskedRecords):\r\n",
      "                mgr = _masked_rec_array_to_mgr(data, index, columns, dtype,\r\n",
      "                                               copy)\r\n",
      "\r\n",
      "            # a masked array\r\n",
      "            else:\r\n",
      "                mask = ma.getmaskarray(data)\r\n",
      "                if mask.any():\r\n",
      "                    data, fill_value = maybe_upcast(data, copy=True)\r\n",
      "                    data[mask] = fill_value\r\n",
      "                else:\r\n",
      "                    data = data.copy()\r\n",
      "                mgr = self._init_ndarray(data, index, columns, dtype=dtype,\r\n",
      "                                         copy=copy)\r\n",
      "\r\n",
      "        elif isinstance(data, (np.ndarray, Series, Index)):\r\n",
      "            if data.dtype.names:\r\n",
      "                data_columns = list(data.dtype.names)\r\n",
      "                data = dict((k, data[k]) for k in data_columns)\r\n",
      "                if columns is None:\r\n",
      "                    columns = data_columns\r\n",
      "                mgr = self._init_dict(data, index, columns, dtype=dtype)\r\n",
      "            elif getattr(data, 'name', None) is not None:\r\n",
      "                mgr = self._init_dict({data.name: data}, index, columns,\r\n",
      "                                      dtype=dtype)\r\n",
      "            else:\r\n",
      "                mgr = self._init_ndarray(data, index, columns, dtype=dtype,\r\n",
      "                                         copy=copy)\r\n",
      "        elif isinstance(data, (list, types.GeneratorType)):\r\n",
      "            if isinstance(data, types.GeneratorType):\r\n",
      "                data = list(data)\r\n",
      "            if len(data) > 0:\r\n",
      "                if is_list_like(data[0]) and getattr(data[0], 'ndim', 1) == 1:\r\n",
      "                    if is_named_tuple(data[0]) and columns is None:\r\n",
      "                        columns = data[0]._fields\r\n",
      "                    arrays, columns = _to_arrays(data, columns, dtype=dtype)\r\n",
      "                    columns = _ensure_index(columns)\r\n",
      "\r\n",
      "                    # set the index\r\n",
      "                    if index is None:\r\n",
      "                        if isinstance(data[0], Series):\r\n",
      "                            index = _get_names_from_index(data)\r\n",
      "                        elif isinstance(data[0], Categorical):\r\n",
      "                            index = _default_index(len(data[0]))\r\n",
      "                        else:\r\n",
      "                            index = _default_index(len(data))\r\n",
      "\r\n",
      "                    mgr = _arrays_to_mgr(arrays, columns, index, columns,\r\n",
      "                                         dtype=dtype)\r\n",
      "                else:\r\n",
      "                    mgr = self._init_ndarray(data, index, columns, dtype=dtype,\r\n",
      "                                             copy=copy)\r\n",
      "            else:\r\n",
      "                mgr = self._init_dict({}, index, columns, dtype=dtype)\r\n",
      "        elif isinstance(data, collections.Iterator):\r\n",
      "            raise TypeError(\"data argument can't be an iterator\")\r\n",
      "        else:\r\n",
      "            try:\r\n",
      "                arr = np.array(data, dtype=dtype, copy=copy)\r\n",
      "            except (ValueError, TypeError) as e:\r\n",
      "                exc = TypeError('DataFrame constructor called with '\r\n",
      "                                'incompatible data and dtype: %s' % e)\r\n",
      "                raise_with_traceback(exc)\r\n",
      "\r\n",
      "            if arr.ndim == 0 and index is not None and columns is not None:\r\n",
      "                values = cast_scalar_to_array((len(index), len(columns)),\r\n",
      "                                              data, dtype=dtype)\r\n",
      "                mgr = self._init_ndarray(values, index, columns,\r\n",
      "                                         dtype=values.dtype, copy=False)\r\n",
      "            else:\r\n",
      "                raise ValueError('DataFrame constructor not properly called!')\r\n",
      "\r\n",
      "        NDFrame.__init__(self, mgr, fastpath=True)\r\n",
      "\r\n",
      "    def _init_dict(self, data, index, columns, dtype=None):\r\n",
      "        \"\"\"\r\n",
      "        Segregate Series based on type and coerce into matrices.\r\n",
      "        Needs to handle a lot of exceptional cases.\r\n",
      "        \"\"\"\r\n",
      "        if columns is not None:\r\n",
      "            columns = _ensure_index(columns)\r\n",
      "\r\n",
      "            # GH10856\r\n",
      "            # raise ValueError if only scalars in dict\r\n",
      "            if index is None:\r\n",
      "                extract_index(list(data.values()))\r\n",
      "\r\n",
      "            # prefilter if columns passed\r\n",
      "            data = dict((k, v) for k, v in compat.iteritems(data)\r\n",
      "                        if k in columns)\r\n",
      "\r\n",
      "            if index is None:\r\n",
      "                index = extract_index(list(data.values()))\r\n",
      "\r\n",
      "            else:\r\n",
      "                index = _ensure_index(index)\r\n",
      "\r\n",
      "            arrays = []\r\n",
      "            data_names = []\r\n",
      "            for k in columns:\r\n",
      "                if k not in data:\r\n",
      "                    # no obvious \"empty\" int column\r\n",
      "                    if dtype is not None and issubclass(dtype.type,\r\n",
      "                                                        np.integer):\r\n",
      "                        continue\r\n",
      "\r\n",
      "                    if dtype is None:\r\n",
      "                        # 1783\r\n",
      "                        v = np.empty(len(index), dtype=object)\r\n",
      "                    elif np.issubdtype(dtype, np.flexible):\r\n",
      "                        v = np.empty(len(index), dtype=object)\r\n",
      "                    else:\r\n",
      "                        v = np.empty(len(index), dtype=dtype)\r\n",
      "\r\n",
      "                    v.fill(np.nan)\r\n",
      "                else:\r\n",
      "                    v = data[k]\r\n",
      "                data_names.append(k)\r\n",
      "                arrays.append(v)\r\n",
      "\r\n",
      "        else:\r\n",
      "            keys = list(data.keys())\r\n",
      "            if not isinstance(data, OrderedDict):\r\n",
      "                keys = _try_sort(keys)\r\n",
      "            columns = data_names = Index(keys)\r\n",
      "            arrays = [data[k] for k in keys]\r\n",
      "\r\n",
      "        return _arrays_to_mgr(arrays, data_names, index, columns, dtype=dtype)\r\n",
      "\r\n",
      "    def _init_ndarray(self, values, index, columns, dtype=None, copy=False):\r\n",
      "        # input must be a ndarray, list, Series, index\r\n",
      "\r\n",
      "        if isinstance(values, Series):\r\n",
      "            if columns is None:\r\n",
      "                if values.name is not None:\r\n",
      "                    columns = [values.name]\r\n",
      "            if index is None:\r\n",
      "                index = values.index\r\n",
      "            else:\r\n",
      "                values = values.reindex(index)\r\n",
      "\r\n",
      "            # zero len case (GH #2234)\r\n",
      "            if not len(values) and columns is not None and len(columns):\r\n",
      "                values = np.empty((0, 1), dtype=object)\r\n",
      "\r\n",
      "        # helper to create the axes as indexes\r\n",
      "        def _get_axes(N, K, index=index, columns=columns):\r\n",
      "            # return axes or defaults\r\n",
      "\r\n",
      "            if index is None:\r\n",
      "                index = _default_index(N)\r\n",
      "            else:\r\n",
      "                index = _ensure_index(index)\r\n",
      "\r\n",
      "            if columns is None:\r\n",
      "                columns = _default_index(K)\r\n",
      "            else:\r\n",
      "                columns = _ensure_index(columns)\r\n",
      "            return index, columns\r\n",
      "\r\n",
      "        # we could have a categorical type passed or coerced to 'category'\r\n",
      "        # recast this to an _arrays_to_mgr\r\n",
      "        if (is_categorical_dtype(getattr(values, 'dtype', None)) or\r\n",
      "                is_categorical_dtype(dtype)):\r\n",
      "\r\n",
      "            if not hasattr(values, 'dtype'):\r\n",
      "                values = _prep_ndarray(values, copy=copy)\r\n",
      "                values = values.ravel()\r\n",
      "            elif copy:\r\n",
      "                values = values.copy()\r\n",
      "\r\n",
      "            index, columns = _get_axes(len(values), 1)\r\n",
      "            return _arrays_to_mgr([values], columns, index, columns,\r\n",
      "                                  dtype=dtype)\r\n",
      "        elif is_datetimetz(values):\r\n",
      "            return self._init_dict({0: values}, index, columns, dtype=dtype)\r\n",
      "\r\n",
      "        # by definition an array here\r\n",
      "        # the dtypes will be coerced to a single dtype\r\n",
      "        values = _prep_ndarray(values, copy=copy)\r\n",
      "\r\n",
      "        if dtype is not None:\r\n",
      "            if not is_dtype_equal(values.dtype, dtype):\r\n",
      "                try:\r\n",
      "                    values = values.astype(dtype)\r\n",
      "                except Exception as orig:\r\n",
      "                    e = ValueError(\"failed to cast to '%s' (Exception was: %s)\"\r\n",
      "                                   % (dtype, orig))\r\n",
      "                    raise_with_traceback(e)\r\n",
      "\r\n",
      "        index, columns = _get_axes(*values.shape)\r\n",
      "        values = values.T\r\n",
      "\r\n",
      "        # if we don't have a dtype specified, then try to convert objects\r\n",
      "        # on the entire block; this is to convert if we have datetimelike's\r\n",
      "        # embedded in an object type\r\n",
      "        if dtype is None and is_object_dtype(values):\r\n",
      "            values = maybe_infer_to_datetimelike(values)\r\n",
      "\r\n",
      "        return create_block_manager_from_blocks([values], [columns, index])\r\n",
      "\r\n",
      "    @property\r\n",
      "    def axes(self):\r\n",
      "        \"\"\"\r\n",
      "        Return a list with the row axis labels and column axis labels as the\r\n",
      "        only members. They are returned in that order.\r\n",
      "        \"\"\"\r\n",
      "        return [self.index, self.columns]\r\n",
      "\r\n",
      "    @property\r\n",
      "    def shape(self):\r\n",
      "        \"\"\"\r\n",
      "        Return a tuple representing the dimensionality of the DataFrame.\r\n",
      "        \"\"\"\r\n",
      "        return len(self.index), len(self.columns)\r\n",
      "\r\n",
      "    def _repr_fits_vertical_(self):\r\n",
      "        \"\"\"\r\n",
      "        Check length against max_rows.\r\n",
      "        \"\"\"\r\n",
      "        max_rows = get_option(\"display.max_rows\")\r\n",
      "        return len(self) <= max_rows\r\n",
      "\r\n",
      "    def _repr_fits_horizontal_(self, ignore_width=False):\r\n",
      "        \"\"\"\r\n",
      "        Check if full repr fits in horizontal boundaries imposed by the display\r\n",
      "        options width and max_columns. In case off non-interactive session, no\r\n",
      "        boundaries apply.\r\n",
      "\r\n",
      "        ignore_width is here so ipnb+HTML output can behave the way\r\n",
      "        users expect. display.max_columns remains in effect.\r\n",
      "        GH3541, GH3573\r\n",
      "        \"\"\"\r\n",
      "\r\n",
      "        width, height = console.get_console_size()\r\n",
      "        max_columns = get_option(\"display.max_columns\")\r\n",
      "        nb_columns = len(self.columns)\r\n",
      "\r\n",
      "        # exceed max columns\r\n",
      "        if ((max_columns and nb_columns > max_columns) or\r\n",
      "                ((not ignore_width) and width and nb_columns > (width // 2))):\r\n",
      "            return False\r\n",
      "\r\n",
      "        # used by repr_html under IPython notebook or scripts ignore terminal\r\n",
      "        # dims\r\n",
      "        if ignore_width or not com.in_interactive_session():\r\n",
      "            return True\r\n",
      "\r\n",
      "        if (get_option('display.width') is not None or\r\n",
      "                com.in_ipython_frontend()):\r\n",
      "            # check at least the column row for excessive width\r\n",
      "            max_rows = 1\r\n",
      "        else:\r\n",
      "            max_rows = get_option(\"display.max_rows\")\r\n",
      "\r\n",
      "        # when auto-detecting, so width=None and not in ipython front end\r\n",
      "        # check whether repr fits horizontal by actualy checking\r\n",
      "        # the width of the rendered repr\r\n",
      "        buf = StringIO()\r\n",
      "\r\n",
      "        # only care about the stuff we'll actually print out\r\n",
      "        # and to_string on entire frame may be expensive\r\n",
      "        d = self\r\n",
      "\r\n",
      "        if not (max_rows is None):  # unlimited rows\r\n",
      "            # min of two, where one may be None\r\n",
      "            d = d.iloc[:min(max_rows, len(d))]\r\n",
      "        else:\r\n",
      "            return True\r\n",
      "\r\n",
      "        d.to_string(buf=buf)\r\n",
      "        value = buf.getvalue()\r\n",
      "        repr_width = max([len(l) for l in value.split('\\n')])\r\n",
      "\r\n",
      "        return repr_width < width\r\n",
      "\r\n",
      "    def _info_repr(self):\r\n",
      "        \"\"\"True if the repr should show the info view.\"\"\"\r\n",
      "        info_repr_option = (get_option(\"display.large_repr\") == \"info\")\r\n",
      "        return info_repr_option and not (self._repr_fits_horizontal_() and\r\n",
      "                                         self._repr_fits_vertical_())\r\n",
      "\r\n",
      "    def __unicode__(self):\r\n",
      "        \"\"\"\r\n",
      "        Return a string representation for a particular DataFrame\r\n",
      "\r\n",
      "        Invoked by unicode(df) in py2 only. Yields a Unicode String in both\r\n",
      "        py2/py3.\r\n",
      "        \"\"\"\r\n",
      "        buf = StringIO(u(\"\"))\r\n",
      "        if self._info_repr():\r\n",
      "            self.info(buf=buf)\r\n",
      "            return buf.getvalue()\r\n",
      "\r\n",
      "        max_rows = get_option(\"display.max_rows\")\r\n",
      "        max_cols = get_option(\"display.max_columns\")\r\n",
      "        show_dimensions = get_option(\"display.show_dimensions\")\r\n",
      "        if get_option(\"display.expand_frame_repr\"):\r\n",
      "            width, _ = console.get_console_size()\r\n",
      "        else:\r\n",
      "            width = None\r\n",
      "        self.to_string(buf=buf, max_rows=max_rows, max_cols=max_cols,\r\n",
      "                       line_width=width, show_dimensions=show_dimensions)\r\n",
      "\r\n",
      "        return buf.getvalue()\r\n",
      "\r\n",
      "    def _repr_html_(self):\r\n",
      "        \"\"\"\r\n",
      "        Return a html representation for a particular DataFrame.\r\n",
      "        Mainly for IPython notebook.\r\n",
      "        \"\"\"\r\n",
      "        # qtconsole doesn't report its line width, and also\r\n",
      "        # behaves badly when outputting an HTML table\r\n",
      "        # that doesn't fit the window, so disable it.\r\n",
      "        # XXX: In IPython 3.x and above, the Qt console will not attempt to\r\n",
      "        # display HTML, so this check can be removed when support for\r\n",
      "        # IPython 2.x is no longer needed.\r\n",
      "        if com.in_qtconsole():\r\n",
      "            # 'HTML output is disabled in QtConsole'\r\n",
      "            return None\r\n",
      "\r\n",
      "        if self._info_repr():\r\n",
      "            buf = StringIO(u(\"\"))\r\n",
      "            self.info(buf=buf)\r\n",
      "            # need to escape the <class>, should be the first line.\r\n",
      "            val = buf.getvalue().replace('<', r'&lt;', 1)\r\n",
      "            val = val.replace('>', r'&gt;', 1)\r\n",
      "            return '<pre>' + val + '</pre>'\r\n",
      "\r\n",
      "        if get_option(\"display.notebook_repr_html\"):\r\n",
      "            max_rows = get_option(\"display.max_rows\")\r\n",
      "            max_cols = get_option(\"display.max_columns\")\r\n",
      "            show_dimensions = get_option(\"display.show_dimensions\")\r\n",
      "\r\n",
      "            return self.to_html(max_rows=max_rows, max_cols=max_cols,\r\n",
      "                                show_dimensions=show_dimensions, notebook=True)\r\n",
      "        else:\r\n",
      "            return None\r\n",
      "\r\n",
      "    @property\r\n",
      "    def style(self):\r\n",
      "        \"\"\"\r\n",
      "        Property returning a Styler object containing methods for\r\n",
      "        building a styled HTML representation fo the DataFrame.\r\n",
      "\r\n",
      "        See Also\r\n",
      "        --------\r\n",
      "        pandas.io.formats.style.Styler\r\n",
      "        \"\"\"\r\n",
      "        from pandas.io.formats.style import Styler\r",
      "\r\n",
      "        return Styler(self)\r\n",
      "\r\n",
      "    def iteritems(self):\r\n",
      "        \"\"\"\r\n",
      "        Iterator over (column name, Series) pairs.\r\n",
      "\r\n",
      "        See also\r\n",
      "        --------\r\n",
      "        iterrows : Iterate over DataFrame rows as (index, Series) pairs.\r\n",
      "        itertuples : Iterate over DataFrame rows as namedtuples of the values.\r\n",
      "\r\n",
      "        \"\"\"\r\n",
      "        if self.columns.is_unique and hasattr(self, '_item_cache'):\r\n",
      "            for k in self.columns:\r\n",
      "                yield k, self._get_item_cache(k)\r\n",
      "        else:\r\n",
      "            for i, k in enumerate(self.columns):\r\n",
      "                yield k, self._ixs(i, axis=1)\r\n",
      "\r\n",
      "    def iterrows(self):\r\n",
      "        \"\"\"\r\n",
      "        Iterate over DataFrame rows as (index, Series) pairs.\r\n",
      "\r\n",
      "        Notes\r\n",
      "        -----\r\n",
      "\r\n",
      "        1. Because ``iterrows`` returns a Series for each row,\r\n",
      "           it does **not** preserve dtypes across the rows (dtypes are\r\n",
      "           preserved across columns for DataFrames). For example,\r\n",
      "\r\n",
      "           >>> df = pd.DataFrame([[1, 1.5]], columns=['int', 'float'])\r\n",
      "           >>> row = next(df.iterrows())[1]\r\n",
      "           >>> row\r\n",
      "           int      1.0\r\n",
      "           float    1.5\r\n",
      "           Name: 0, dtype: float64\r\n",
      "           >>> print(row['int'].dtype)\r\n",
      "           float64\r\n",
      "           >>> print(df['int'].dtype)\r\n",
      "           int64\r\n",
      "\r\n",
      "           To preserve dtypes while iterating over the rows, it is better\r\n",
      "           to use :meth:`itertuples` which returns namedtuples of the values\r\n",
      "           and which is generally faster than ``iterrows``.\r\n",
      "\r\n",
      "        2. You should **never modify** something you are iterating over.\r\n",
      "           This is not guaranteed to work in all cases. Depending on the\r\n",
      "           data types, the iterator returns a copy and not a view, and writing\r\n",
      "           to it will have no effect.\r\n",
      "\r\n",
      "        Returns\r\n",
      "        -------\r\n",
      "        it : generator\r\n",
      "            A generator that iterates over the rows of the frame.\r\n",
      "\r\n",
      "        See also\r\n",
      "        --------\r\n",
      "        itertuples : Iterate over DataFrame rows as namedtuples of the values.\r\n",
      "        iteritems : Iterate over (column name, Series) pairs.\r\n",
      "\r\n",
      "        \"\"\"\r\n",
      "        columns = self.columns\r\n",
      "        klass = self._constructor_sliced\r\n",
      "        for k, v in zip(self.index, self.values):\r\n",
      "            s = klass(v, index=columns, name=k)\r\n",
      "            yield k, s\r\n",
      "\r\n",
      "    def itertuples(self, index=True, name=\"Pandas\"):\r\n",
      "        \"\"\"\r\n",
      "        Iterate over DataFrame rows as namedtuples, with index value as first\r\n",
      "        element of the tuple.\r\n",
      "\r\n",
      "        Parameters\r\n",
      "        ----------\r\n",
      "        index : boolean, default True\r\n",
      "            If True, return the index as the first element of the tuple.\r\n",
      "        name : string, default \"Pandas\"\r\n",
      "            The name of the returned namedtuples or None to return regular\r\n",
      "            tuples.\r\n",
      "\r\n",
      "        Notes\r\n",
      "        -----\r\n",
      "        The column names will be renamed to positional names if they are\r\n",
      "        invalid Python identifiers, repeated, or start with an underscore.\r\n",
      "        With a large number of columns (>255), regular tuples are returned.\r\n",
      "\r\n",
      "        See also\r\n",
      "        --------\r\n",
      "        iterrows : Iterate over DataFrame rows as (index, Series) pairs.\r\n",
      "        iteritems : Iterate over (column name, Series) pairs.\r\n",
      "\r\n",
      "        Examples\r\n",
      "        --------\r\n",
      "\r\n",
      "        >>> df = pd.DataFrame({'col1': [1, 2], 'col2': [0.1, 0.2]},\r\n",
      "                              index=['a', 'b'])\r\n",
      "        >>> df\r\n",
      "           col1  col2\r\n",
      "        a     1   0.1\r\n",
      "        b     2   0.2\r\n",
      "        >>> for row in df.itertuples():\r\n",
      "        ...     print(row)\r\n",
      "        ...\r\n",
      "        Pandas(Index='a', col1=1, col2=0.10000000000000001)\r\n",
      "        Pandas(Index='b', col1=2, col2=0.20000000000000001)\r\n",
      "\r\n",
      "        \"\"\"\r\n",
      "        arrays = []\r\n",
      "        fields = []\r\n",
      "        if index:\r\n",
      "            arrays.append(self.index)\r\n",
      "            fields.append(\"Index\")\r\n",
      "\r\n",
      "        # use integer indexing because of possible duplicate column names\r\n",
      "        arrays.extend(self.iloc[:, k] for k in range(len(self.columns)))\r\n",
      "\r\n",
      "        # Python 3 supports at most 255 arguments to constructor, and\r\n",
      "        # things get slow with this many fields in Python 2\r\n",
      "        if name is not None and len(self.columns) + index < 256:\r\n",
      "            # `rename` is unsupported in Python 2.6\r\n",
      "            try:\r\n",
      "                itertuple = collections.namedtuple(name,\r\n",
      "                                                   fields + list(self.columns),\r\n",
      "                                                   rename=True)\r\n",
      "                return map(itertuple._make, zip(*arrays))\r\n",
      "            except Exception:\r\n",
      "                pass\r\n",
      "\r\n",
      "        # fallback to regular tuples\r\n",
      "        return zip(*arrays)\r\n",
      "\r\n",
      "    items = iteritems\r\n",
      "\r\n",
      "    def __len__(self):\r\n",
      "        \"\"\"Returns length of info axis, but here we use the index \"\"\"\r\n",
      "        return len(self.index)\r\n",
      "\r\n",
      "    def dot(self, other):\r\n",
      "        \"\"\"\r\n",
      "        Matrix multiplication with DataFrame or Series objects\r\n",
      "\r\n",
      "        Parameters\r\n",
      "        ----------\r\n",
      "        other : DataFrame or Series\r\n",
      "\r\n",
      "        Returns\r\n",
      "        -------\r\n",
      "        dot_product : DataFrame or Series\r\n",
      "        \"\"\"\r\n",
      "        if isinstance(other, (Series, DataFrame)):\r\n",
      "            common = self.columns.union(other.index)\r\n",
      "            if (len(common) > len(self.columns) or\r\n",
      "                    len(common) > len(other.index)):\r\n",
      "                raise ValueError('matrices are not aligned')\r\n",
      "\r\n",
      "            left = self.reindex(columns=common, copy=False)\r\n",
      "            right = other.reindex(index=common, copy=False)\r\n",
      "            lvals = left.values\r\n",
      "            rvals = right.values\r\n",
      "        else:\r\n",
      "            left = self\r\n",
      "            lvals = self.values\r\n",
      "            rvals = np.asarray(other)\r\n",
      "            if lvals.shape[1] != rvals.shape[0]:\r\n",
      "                raise ValueError('Dot product shape mismatch, %s vs %s' %\r\n",
      "                                 (lvals.shape, rvals.shape))\r\n",
      "\r\n",
      "        if isinstance(other, DataFrame):\r\n",
      "            return self._constructor(np.dot(lvals, rvals), index=left.index,\r\n",
      "                                     columns=other.columns)\r\n",
      "        elif isinstance(other, Series):\r\n",
      "            return Series(np.dot(lvals, rvals), index=left.index)\r\n",
      "        elif isinstance(rvals, (np.ndarray, Index)):\r\n",
      "            result = np.dot(lvals, rvals)\r\n",
      "            if result.ndim == 2:\r\n",
      "                return self._constructor(result, index=left.index)\r\n",
      "            else:\r\n",
      "                return Series(result, index=left.index)\r\n",
      "        else:  # pragma: no cover\r\n",
      "            raise TypeError('unsupported type: %s' % type(other))\r\n",
      "\r\n",
      "    # ----------------------------------------------------------------------\r\n",
      "    # IO methods (to / from other formats)\r\n",
      "\r\n",
      "    @classmethod\r\n",
      "    def from_dict(cls, data, orient='columns', dtype=None):\r\n",
      "        \"\"\"\r\n",
      "        Construct DataFrame from dict of array-like or dicts\r\n",
      "\r\n",
      "        Parameters\r\n",
      "        ----------\r\n",
      "        data : dict\r\n",
      "            {field : array-like} or {field : dict}\r\n",
      "        orient : {'columns', 'index'}, default 'columns'\r\n",
      "            The \"orientation\" of the data. If the keys of the passed dict\r\n",
      "            should be the columns of the resulting DataFrame, pass 'columns'\r\n",
      "            (default). Otherwise if the keys should be rows, pass 'index'.\r\n",
      "        dtype : dtype, default None\r\n",
      "            Data type to force, otherwise infer\r\n",
      "\r\n",
      "        Returns\r\n",
      "        -------\r\n",
      "        DataFrame\r\n",
      "        \"\"\"\r\n",
      "        index, columns = None, None\r\n",
      "        orient = orient.lower()\r\n",
      "        if orient == 'index':\r\n",
      "            if len(data) > 0:\r\n",
      "                # TODO speed up Series case\r\n",
      "                if isinstance(list(data.values())[0], (Series, dict)):\r\n",
      "                    data = _from_nested_dict(data)\r\n",
      "                else:\r\n",
      "                    data, index = list(data.values()), list(data.keys())\r\n",
      "        elif orient != 'columns':  # pragma: no cover\r\n",
      "            raise ValueError('only recognize index or columns for orient')\r\n",
      "\r\n",
      "        return cls(data, index=index, columns=columns, dtype=dtype)\r\n",
      "\r\n",
      "    def to_dict(self, orient='dict', into=dict):\r\n",
      "        \"\"\"Convert DataFrame to dictionary.\r\n",
      "\r\n",
      "        Parameters\r\n",
      "        ----------\r\n",
      "        orient : str {'dict', 'list', 'series', 'split', 'records', 'index'}\r\n",
      "            Determines the type of the values of the dictionary.\r\n",
      "\r\n",
      "            - dict (default) : dict like {column -> {index -> value}}\r\n",
      "            - list : dict like {column -> [values]}\r\n",
      "            - series : dict like {column -> Series(values)}\r\n",
      "            - split : dict like\r\n",
      "              {index -> [index], columns -> [columns], data -> [values]}\r\n",
      "            - records : list like\r\n",
      "              [{column -> value}, ... , {column -> value}]\r\n",
      "            - index : dict like {index -> {column -> value}}\r\n",
      "\r\n",
      "              .. versionadded:: 0.17.0\r\n",
      "\r\n",
      "            Abbreviations are allowed. `s` indicates `series` and `sp`\r\n",
      "            indicates `split`.\r\n",
      "\r\n",
      "        into : class, default dict\r\n",
      "            The collections.Mapping subclass used for all Mappings\r\n",
      "            in the return value.  Can be the actual class or an empty\r\n",
      "            instance of the mapping type you want.  If you want a\r\n",
      "            collections.defaultdict, you must pass it initialized.\r\n",
      "\r\n",
      "            .. versionadded:: 0.21.0\r\n",
      "\r\n",
      "        Returns\r\n",
      "        -------\r\n",
      "        result : collections.Mapping like {column -> {index -> value}}\r\n",
      "\r\n",
      "        Examples\r\n",
      "        --------\r\n",
      "        >>> df = pd.DataFrame(\r\n",
      "                {'col1': [1, 2], 'col2': [0.5, 0.75]}, index=['a', 'b'])\r\n",
      "        >>> df\r\n",
      "           col1  col2\r\n",
      "        a     1   0.1\r\n",
      "        b     2   0.2\r\n",
      "        >>> df.to_dict()\r\n",
      "        {'col1': {'a': 1, 'b': 2}, 'col2': {'a': 0.5, 'b': 0.75}}\r\n",
      "\r\n",
      "        You can specify the return orientation.\r\n",
      "\r\n",
      "        >>> df.to_dict('series')\r\n",
      "        {'col1': a    1\r\n",
      "        b    2\r\n",
      "        Name: col1, dtype: int64, 'col2': a    0.50\r\n",
      "        b    0.75\r\n",
      "        Name: col2, dtype: float64}\r\n",
      "        >>> df.to_dict('split')\r\n",
      "        {'columns': ['col1', 'col2'],\r\n",
      "        'data': [[1.0, 0.5], [2.0, 0.75]],\r\n",
      "        'index': ['a', 'b']}\r\n",
      "        >>> df.to_dict('records')\r\n",
      "        [{'col1': 1.0, 'col2': 0.5}, {'col1': 2.0, 'col2': 0.75}]\r\n",
      "        >>> df.to_dict('index')\r\n",
      "        {'a': {'col1': 1.0, 'col2': 0.5}, 'b': {'col1': 2.0, 'col2': 0.75}}\r\n",
      "\r\n",
      "        You can also specify the mapping type.\r\n",
      "\r\n",
      "        >>> from collections import OrderedDict, defaultdict\r\n",
      "        >>> df.to_dict(into=OrderedDict)\r\n",
      "        OrderedDict([('col1', OrderedDict([('a', 1), ('b', 2)])),\r\n",
      "                   ('col2', OrderedDict([('a', 0.5), ('b', 0.75)]))])\r\n",
      "\r\n",
      "        If you want a `defaultdict`, you need to initialize it:\r\n",
      "\r\n",
      "        >>> dd = defaultdict(list)\r\n",
      "        >>> df.to_dict('records', into=dd)\r\n",
      "        [defaultdict(<type 'list'>, {'col2': 0.5, 'col1': 1.0}),\r\n",
      "        defaultdict(<type 'list'>, {'col2': 0.75, 'col1': 2.0})]\r\n",
      "        \"\"\"\r\n",
      "        if not self.columns.is_unique:\r\n",
      "            warnings.warn(\"DataFrame columns are not unique, some \"\r\n",
      "                          \"columns will be omitted.\", UserWarning,\r\n",
      "                          stacklevel=2)\r\n",
      "        # GH16122\r\n",
      "        into_c = standardize_mapping(into)\r\n",
      "        if orient.lower().startswith('d'):\r\n",
      "            return into_c(\r\n",
      "                (k, v.to_dict(into)) for k, v in compat.iteritems(self))\r\n",
      "        elif orient.lower().startswith('l'):\r\n",
      "            return into_c((k, v.tolist()) for k, v in compat.iteritems(self))\r\n",
      "        elif orient.lower().startswith('sp'):\r\n",
      "            return into_c((('index', self.index.tolist()),\r\n",
      "                           ('columns', self.columns.tolist()),\r\n",
      "                           ('data', lib.map_infer(self.values.ravel(),\r\n",
      "                                                  _maybe_box_datetimelike)\r\n",
      "                            .reshape(self.values.shape).tolist())))\r\n",
      "        elif orient.lower().startswith('s'):\r\n",
      "            return into_c((k, _maybe_box_datetimelike(v))\r\n",
      "                          for k, v in compat.iteritems(self))\r\n",
      "        elif orient.lower().startswith('r'):\r\n",
      "            return [into_c((k, _maybe_box_datetimelike(v))\r\n",
      "                           for k, v in zip(self.columns, np.atleast_1d(row)))\r\n",
      "                    for row in self.values]\r\n",
      "        elif orient.lower().startswith('i'):\r\n",
      "            return into_c((k, v.to_dict(into)) for k, v in self.iterrows())\r\n",
      "        else:\r\n",
      "            raise ValueError(\"orient '%s' not understood\" % orient)\r\n",
      "\r\n",
      "    def to_gbq(self, destination_table, project_id, chunksize=10000,\r\n",
      "               verbose=True, reauth=False, if_exists='fail', private_key=None):\r\n",
      "        \"\"\"Write a DataFrame to a Google BigQuery table.\r\n",
      "\r\n",
      "        The main method a user calls to export pandas DataFrame contents to\r\n",
      "        Google BigQuery table.\r\n",
      "\r\n",
      "        Google BigQuery API Client Library v2 for Python is used.\r\n",
      "        Documentation is available `here\r\n",
      "        <https://developers.google.com/api-client-library/python/apis/bigquery/v2>`__\r\n",
      "\r\n",
      "        Authentication to the Google BigQuery service is via OAuth 2.0.\r\n",
      "\r\n",
      "        - If \"private_key\" is not provided:\r\n",
      "\r\n",
      "          By default \"application default credentials\" are used.\r\n",
      "\r\n",
      "          If default application credentials are not found or are restrictive,\r\n",
      "          user account credentials are used. In this case, you will be asked to\r\n",
      "          grant permissions for product name 'pandas GBQ'.\r\n",
      "\r\n",
      "        - If \"private_key\" is provided:\r\n",
      "\r\n",
      "          Service account credentials will be used to authenticate.\r\n",
      "\r\n",
      "        Parameters\r\n",
      "        ----------\r\n",
      "        dataframe : DataFrame\r\n",
      "            DataFrame to be written\r\n",
      "        destination_table : string\r\n",
      "            Name of table to be written, in the form 'dataset.tablename'\r\n",
      "        project_id : str\r\n",
      "            Google BigQuery Account project ID.\r\n",
      "        chunksize : int (default 10000)\r\n",
      "            Number of rows to be inserted in each chunk from the dataframe.\r\n",
      "        verbose : boolean (default True)\r\n",
      "            Show percentage complete\r\n",
      "        reauth : boolean (default False)\r\n",
      "            Force Google BigQuery to reauthenticate the user. This is useful\r\n",
      "            if multiple accounts are used.\r\n",
      "        if_exists : {'fail', 'replace', 'append'}, default 'fail'\r\n",
      "            'fail': If table exists, do nothing.\r\n",
      "            'replace': If table exists, drop it, recreate it, and insert data.\r\n",
      "            'append': If table exists, insert data. Create if does not exist.\r\n",
      "        private_key : str (optional)\r\n",
      "            Service account private key in JSON format. Can be file path\r\n",
      "            or string contents. This is useful for remote server\r\n",
      "            authentication (eg. jupyter iPython notebook on remote host)\r\n",
      "        \"\"\"\r\n",
      "\r\n",
      "        from pandas.io import gbq\r\n",
      "        return gbq.to_gbq(self, destination_table, project_id=project_id,\r\n",
      "                          chunksize=chunksize, verbose=verbose, reauth=reauth,\r\n",
      "                          if_exists=if_exists, private_key=private_key)\r\n",
      "\r\n",
      "    @classmethod\r\n",
      "    def from_records(cls, data, index=None, exclude=None, columns=None,\r\n",
      "                     coerce_float=False, nrows=None):\r\n",
      "        \"\"\"\r\n",
      "        Convert structured or record ndarray to DataFrame\r\n",
      "\r\n",
      "        Parameters\r\n",
      "        ----------\r\n",
      "        data : ndarray (structured dtype), list of tuples, dict, or DataFrame\r\n",
      "        index : string, list of fields, array-like\r\n",
      "            Field of array to use as the index, alternately a specific set of\r\n",
      "            input labels to use\r\n",
      "        exclude : sequence, default None\r\n",
      "            Columns or fields to exclude\r\n",
      "        columns : sequence, default None\r\n",
      "            Column names to use. If the passed data do not have names\r\n",
      "            associated with them, this argument provides names for the\r\n",
      "            columns. Otherwise this argument indicates the order of the columns\r\n",
      "            in the result (any names not found in the data will become all-NA\r\n",
      "            columns)\r\n",
      "        coerce_float : boolean, default False\r\n",
      "            Attempt to convert values of non-string, non-numeric objects (like\r\n",
      "            decimal.Decimal) to floating point, useful for SQL result sets\r\n",
      "\r\n",
      "        Returns\r\n",
      "        -------\r\n",
      "        df : DataFrame\r\n",
      "        \"\"\"\r\n",
      "\r\n",
      "        # Make a copy of the input columns so we can modify it\r\n",
      "        if columns is not None:\r\n",
      "            columns = _ensure_index(columns)\r\n",
      "\r\n",
      "        if is_iterator(data):\r\n",
      "            if nrows == 0:\r\n",
      "                return cls()\r\n",
      "\r\n",
      "            try:\r\n",
      "                first_row = next(data)\r\n",
      "            except StopIteration:\r\n",
      "                return cls(index=index, columns=columns)\r\n",
      "\r\n",
      "            dtype = None\r\n",
      "            if hasattr(first_row, 'dtype') and first_row.dtype.names:\r\n",
      "                dtype = first_row.dtype\r\n",
      "\r\n",
      "            values = [first_row]\r\n",
      "\r\n",
      "            if nrows is None:\r\n",
      "                values += data\r\n",
      "            else:\r\n",
      "                values.extend(itertools.islice(data, nrows - 1))\r\n",
      "\r\n",
      "            if dtype is not None:\r\n",
      "                data = np.array(values, dtype=dtype)\r\n",
      "            else:\r\n",
      "                data = values\r\n",
      "\r\n",
      "        if isinstance(data, dict):\r\n",
      "            if columns is None:\r\n",
      "                columns = arr_columns = _ensure_index(sorted(data))\r\n",
      "                arrays = [data[k] for k in columns]\r\n",
      "            else:\r\n",
      "                arrays = []\r\n",
      "                arr_columns = []\r\n",
      "                for k, v in compat.iteritems(data):\r\n",
      "                    if k in columns:\r\n",
      "                        arr_columns.append(k)\r\n",
      "                        arrays.append(v)\r\n",
      "\r\n",
      "                arrays, arr_columns = _reorder_arrays(arrays, arr_columns,\r\n",
      "                                                      columns)\r\n",
      "\r\n",
      "        elif isinstance(data, (np.ndarray, DataFrame)):\r\n",
      "            arrays, columns = _to_arrays(data, columns)\r\n",
      "            if columns is not None:\r\n",
      "                columns = _ensure_index(columns)\r\n",
      "            arr_columns = columns\r\n",
      "        else:\r\n",
      "            arrays, arr_columns = _to_arrays(data, columns,\r\n",
      "                                             coerce_float=coerce_float)\r\n",
      "\r\n",
      "            arr_columns = _ensure_index(arr_columns)\r\n",
      "            if columns is not None:\r\n",
      "                columns = _ensure_index(columns)\r\n",
      "            else:\r\n",
      "                columns = arr_columns\r\n",
      "\r\n",
      "        if exclude is None:\r\n",
      "            exclude = set()\r\n",
      "        else:\r\n",
      "            exclude = set(exclude)\r\n",
      "\r\n",
      "        result_index = None\r\n",
      "        if index is not None:\r\n",
      "            if (isinstance(index, compat.string_types) or\r\n",
      "                    not hasattr(index, \"__iter__\")):\r\n",
      "                i = columns.get_loc(index)\r\n",
      "                exclude.add(index)\r\n",
      "                if len(arrays) > 0:\r\n",
      "                    result_index = Index(arrays[i], name=index)\r\n",
      "                else:\r\n",
      "                    result_index = Index([], name=index)\r\n",
      "            else:\r\n",
      "                try:\r\n",
      "                    to_remove = [arr_columns.get_loc(field) for field in index]\r\n",
      "                    index_data = [arrays[i] for i in to_remove]\r\n",
      "                    result_index = _ensure_index_from_sequences(index_data,\r\n",
      "                                                                names=index)\r\n",
      "\r\n",
      "                    exclude.update(index)\r\n",
      "                except Exception:\r\n",
      "                    result_index = index\r\n",
      "\r\n",
      "        if any(exclude):\r\n",
      "            arr_exclude = [x for x in exclude if x in arr_columns]\r\n",
      "            to_remove = [arr_columns.get_loc(col) for col in arr_exclude]\r\n",
      "            arrays = [v for i, v in enumerate(arrays) if i not in to_remove]\r\n",
      "\r\n",
      "            arr_columns = arr_columns.drop(arr_exclude)\r\n",
      "            columns = columns.drop(exclude)\r\n",
      "\r\n",
      "        mgr = _arrays_to_mgr(arrays, arr_columns, result_index, columns)\r\n",
      "\r\n",
      "        return cls(mgr)\r\n",
      "\r\n",
      "    def to_records(self, index=True, convert_datetime64=True):\r\n",
      "        \"\"\"\r\n",
      "        Convert DataFrame to record array. Index will be put in the\r\n",
      "        'index' field of the record array if requested\r\n",
      "\r\n",
      "        Parameters\r\n",
      "        ----------\r\n",
      "        index : boolean, default True\r\n",
      "            Include index in resulting record array, stored in 'index' field\r\n",
      "        convert_datetime64 : boolean, default True\r\n",
      "            Whether to convert the index to datetime.datetime if it is a\r\n",
      "            DatetimeIndex\r\n",
      "\r\n",
      "        Returns\r\n",
      "        -------\r\n",
      "        y : recarray\r\n",
      "        \"\"\"\r\n",
      "        if index:\r\n",
      "            if is_datetime64_any_dtype(self.index) and convert_datetime64:\r\n",
      "                ix_vals = [self.index.to_pydatetime()]\r\n",
      "            else:\r\n",
      "                if isinstance(self.index, MultiIndex):\r\n",
      "                    # array of tuples to numpy cols. copy copy copy\r\n",
      "                    ix_vals = lmap(np.array, zip(*self.index.values))\r\n",
      "                else:\r\n",
      "                    ix_vals = [self.index.values]\r\n",
      "\r\n",
      "            arrays = ix_vals + [self[c].get_values() for c in self.columns]\r\n",
      "\r\n",
      "            count = 0\r\n",
      "            index_names = list(self.index.names)\r\n",
      "            if isinstance(self.index, MultiIndex):\r\n",
      "                for i, n in enumerate(index_names):\r\n",
      "                    if n is None:\r\n",
      "                        index_names[i] = 'level_%d' % count\r\n",
      "                        count += 1\r\n",
      "            elif index_names[0] is None:\r\n",
      "                index_names = ['index']\r\n",
      "            names = (lmap(compat.text_type, index_names) +\r\n",
      "                     lmap(compat.text_type, self.columns))\r\n",
      "        else:\r\n",
      "            arrays = [self[c].get_values() for c in self.columns]\r\n",
      "            names = lmap(compat.text_type, self.columns)\r\n",
      "\r\n",
      "        formats = [v.dtype for v in arrays]\r\n",
      "        return np.rec.fromarrays(\r\n",
      "            arrays,\r\n",
      "            dtype={'names': names, 'formats': formats}\r\n",
      "        )\r\n",
      "\r\n",
      "    @classmethod\r\n",
      "    def from_items(cls, items, columns=None, orient='columns'):\r\n",
      "        \"\"\"\r\n",
      "        Convert (key, value) pairs to DataFrame. The keys will be the axis\r\n",
      "        index (usually the columns, but depends on the specified\r\n",
      "        orientation). The values should be arrays or Series.\r\n",
      "\r\n",
      "        Parameters\r\n",
      "        ----------\r\n",
      "        items : sequence of (key, value) pairs\r\n",
      "            Values should be arrays or Series.\r\n",
      "        columns : sequence of column labels, optional\r\n",
      "            Must be passed if orient='index'.\r\n",
      "        orient : {'columns', 'index'}, default 'columns'\r\n",
      "            The \"orientation\" of the data. If the keys of the\r\n",
      "            input correspond to column labels, pass 'columns'\r\n",
      "            (default). Otherwise if the keys correspond to the index,\r\n",
      "            pass 'index'.\r\n",
      "\r\n",
      "        Returns\r\n",
      "        -------\r\n",
      "        frame : DataFrame\r\n",
      "        \"\"\"\r\n",
      "        keys, values = lzip(*items)\r\n",
      "\r\n",
      "        if orient == 'columns':\r\n",
      "            if columns is not None:\r\n",
      "                columns = _ensure_index(columns)\r\n",
      "\r\n",
      "                idict = dict(items)\r\n",
      "                if len(idict) < len(items):\r\n",
      "                    if not columns.equals(_ensure_index(keys)):\r\n",
      "                        raise ValueError('With non-unique item names, passed '\r\n",
      "                                         'columns must be identical')\r\n",
      "                    arrays = values\r\n",
      "                else:\r\n",
      "                    arrays = [idict[k] for k in columns if k in idict]\r\n",
      "            else:\r\n",
      "                columns = _ensure_index(keys)\r\n",
      "                arrays = values\r\n",
      "\r\n",
      "            return cls._from_arrays(arrays, columns, None)\r\n",
      "        elif orient == 'index':\r\n",
      "            if columns is None:\r\n",
      "                raise TypeError(\"Must pass columns with orient='index'\")\r\n",
      "\r\n",
      "            keys = _ensure_index(keys)\r\n",
      "\r\n",
      "            arr = np.array(values, dtype=object).T\r\n",
      "            data = [lib.maybe_convert_objects(v) for v in arr]\r\n",
      "            return cls._from_arrays(data, columns, keys)\r\n",
      "        else:  # pragma: no cover\r\n",
      "            raise ValueError(\"'orient' must be either 'columns' or 'index'\")\r\n",
      "\r\n",
      "    @classmethod\r\n",
      "    def _from_arrays(cls, arrays, columns, index, dtype=None):\r\n",
      "        mgr = _arrays_to_mgr(arrays, columns, index, columns, dtype=dtype)\r\n",
      "        return cls(mgr)\r\n",
      "\r\n",
      "    @classmethod\r\n",
      "    def from_csv(cls, path, header=0, sep=',', index_col=0, parse_dates=True,\r\n",
      "                 encoding=None, tupleize_cols=None,\r\n",
      "                 infer_datetime_format=False):\r\n",
      "        \"\"\"\r\n",
      "        Read CSV file (DEPRECATED, please use :func:`pandas.read_csv`\r\n",
      "        instead).\r\n",
      "\r\n",
      "        It is preferable to use the more powerful :func:`pandas.read_csv`\r\n",
      "        for most general purposes, but ``from_csv`` makes for an easy\r\n",
      "        roundtrip to and from a file (the exact counterpart of\r\n",
      "        ``to_csv``), especially with a DataFrame of time series data.\r\n",
      "\r\n",
      "        This method only differs from the preferred :func:`pandas.read_csv`\r\n",
      "        in some defaults:\r\n",
      "\r\n",
      "        - `index_col` is ``0`` instead of ``None`` (take first column as index\r\n",
      "          by default)\r\n",
      "        - `parse_dates` is ``True`` instead of ``False`` (try parsing the index\r\n",
      "          as datetime by default)\r\n",
      "\r\n",
      "        So a ``pd.DataFrame.from_csv(path)`` can be replaced by\r\n",
      "        ``pd.read_csv(path, index_col=0, parse_dates=True)``.\r\n",
      "\r\n",
      "        Parameters\r\n",
      "        ----------\r\n",
      "        path : string file path or file handle / StringIO\r\n",
      "        header : int, default 0\r\n",
      "            Row to use as header (skip prior rows)\r\n",
      "        sep : string, default ','\r\n",
      "            Field delimiter\r\n",
      "        index_col : int or sequence, default 0\r\n",
      "            Column to use for index. If a sequence is given, a MultiIndex\r\n",
      "            is used. Different default from read_table\r\n",
      "        parse_dates : boolean, default True\r\n",
      "            Parse dates. Different default from read_table\r\n",
      "        tupleize_cols : boolean, default False\r\n",
      "            write multi_index columns as a list of tuples (if True)\r\n",
      "            or new (expanded format) if False)\r\n",
      "        infer_datetime_format: boolean, default False\r\n",
      "            If True and `parse_dates` is True for a column, try to infer the\r\n",
      "            datetime format based on the first datetime string. If the format\r\n",
      "            can be inferred, there often will be a large parsing speed-up.\r\n",
      "\r\n",
      "        See also\r\n",
      "        --------\r\n",
      "        pandas.read_csv\r\n",
      "\r\n",
      "        Returns\r\n",
      "        -------\r\n",
      "        y : DataFrame\r\n",
      "\r\n",
      "        \"\"\"\r\n",
      "\r\n",
      "        warnings.warn(\"from_csv is deprecated. Please use read_csv(...) \"\r\n",
      "                      \"instead. Note that some of the default arguments are \"\r\n",
      "                      \"different, so please refer to the documentation \"\r\n",
      "                      \"for from_csv when changing your function calls\",\r\n",
      "                      FutureWarning, stacklevel=2)\r\n",
      "\r\n",
      "        from pandas.io.parsers import read_table\r\n",
      "        return read_table(path, header=header, sep=sep,\r\n",
      "                          parse_dates=parse_dates, index_col=index_col,\r\n",
      "                          encoding=encoding, tupleize_cols=tupleize_cols,\r\n",
      "                          infer_datetime_format=infer_datetime_format)\r\n",
      "\r\n",
      "    def to_sparse(self, fill_value=None, kind='block'):\r\n",
      "        \"\"\"\r\n",
      "        Convert to SparseDataFrame\r\n",
      "\r\n",
      "        Parameters\r\n",
      "        ----------\r\n",
      "        fill_value : float, default NaN\r\n",
      "        kind : {'block', 'integer'}\r\n",
      "\r\n",
      "        Returns\r\n",
      "        -------\r\n",
      "        y : SparseDataFrame\r\n",
      "        \"\"\"\r\n",
      "        from pandas.core.sparse.frame import SparseDataFrame\r\n",
      "        return SparseDataFrame(self._series, index=self.index,\r\n",
      "                               columns=self.columns, default_kind=kind,\r\n",
      "                               default_fill_value=fill_value)\r\n",
      "\r\n",
      "    def to_panel(self):\r\n",
      "        \"\"\"\r\n",
      "        Transform long (stacked) format (DataFrame) into wide (3D, Panel)\r\n",
      "        format.\r\n",
      "\r\n",
      "        Currently the index of the DataFrame must be a 2-level MultiIndex. This\r\n",
      "        may be generalized later\r\n",
      "\r\n",
      "        Returns\r\n",
      "        -------\r\n",
      "        panel : Panel\r\n",
      "        \"\"\"\r\n",
      "        # only support this kind for now\r\n",
      "        if (not isinstance(self.index, MultiIndex) or  # pragma: no cover\r\n",
      "                len(self.index.levels) != 2):\r\n",
      "            raise NotImplementedError('Only 2-level MultiIndex are supported.')\r\n",
      "\r\n",
      "        if not self.index.is_unique:\r\n",
      "            raise ValueError(\"Can't convert non-uniquely indexed \"\r\n",
      "                             \"DataFrame to Panel\")\r\n",
      "\r\n",
      "        self._consolidate_inplace()\r\n",
      "\r\n",
      "        # minor axis must be sorted\r\n",
      "        if self.index.lexsort_depth < 2:\r\n",
      "            selfsorted = self.sort_index(level=0)\r\n",
      "        else:\r\n",
      "            selfsorted = self\r\n",
      "\r\n",
      "        major_axis, minor_axis = selfsorted.index.levels\r\n",
      "        major_labels, minor_labels = selfsorted.index.labels\r\n",
      "        shape = len(major_axis), len(minor_axis)\r\n",
      "\r\n",
      "        # preserve names, if any\r\n",
      "        major_axis = major_axis.copy()\r\n",
      "        major_axis.name = self.index.names[0]\r\n",
      "\r\n",
      "        minor_axis = minor_axis.copy()\r\n",
      "        minor_axis.name = self.index.names[1]\r\n",
      "\r\n",
      "        # create new axes\r\n",
      "        new_axes = [selfsorted.columns, major_axis, minor_axis]\r\n",
      "\r\n",
      "        # create new manager\r\n",
      "        new_mgr = selfsorted._data.reshape_nd(axes=new_axes,\r\n",
      "                                              labels=[major_labels,\r\n",
      "                                                      minor_labels],\r\n",
      "                                              shape=shape,\r\n",
      "                                              ref_items=selfsorted.columns)\r\n",
      "\r\n",
      "        return self._constructor_expanddim(new_mgr)\r\n",
      "\r\n",
      "    def to_csv(self, path_or_buf=None, sep=\",\", na_rep='', float_format=None,\r\n",
      "               columns=None, header=True, index=True, index_label=None,\r\n",
      "               mode='w', encoding=None, compression=None, quoting=None,\r\n",
      "               quotechar='\"', line_terminator='\\n', chunksize=None,\r\n",
      "               tupleize_cols=None, date_format=None, doublequote=True,\r\n",
      "               escapechar=None, decimal='.'):\r\n",
      "        r\"\"\"Write DataFrame to a comma-separated values (csv) file\r\n",
      "\r\n",
      "        Parameters\r\n",
      "        ----------\r\n",
      "        path_or_buf : string or file handle, default None\r\n",
      "            File path or object, if None is provided the result is returned as\r\n",
      "            a string.\r\n",
      "        sep : character, default ','\r\n",
      "            Field delimiter for the output file.\r\n",
      "        na_rep : string, default ''\r\n",
      "            Missing data representation\r\n",
      "        float_format : string, default None\r\n",
      "            Format string for floating point numbers\r\n",
      "        columns : sequence, optional\r\n",
      "            Columns to write\r\n",
      "        header : boolean or list of string, default True\r\n",
      "            Write out the column names. If a list of strings is given it is\r\n",
      "            assumed to be aliases for the column names\r\n",
      "        index : boolean, default True\r\n",
      "            Write row names (index)\r\n",
      "        index_label : string or sequence, or False, default None\r\n",
      "            Column label for index column(s) if desired. If None is given, and\r\n",
      "            `header` and `index` are True, then the index names are used. A\r\n",
      "            sequence should be given if the DataFrame uses MultiIndex.  If\r\n",
      "            False do not print fields for index names. Use index_label=False\r\n",
      "            for easier importing in R\r\n",
      "        mode : str\r\n",
      "            Python write mode, default 'w'\r\n",
      "        encoding : string, optional\r\n",
      "            A string representing the encoding to use in the output file,\r\n",
      "            defaults to 'ascii' on Python 2 and 'utf-8' on Python 3.\r\n",
      "        compression : string, optional\r\n",
      "            a string representing the compression to use in the output file,\r\n",
      "            allowed values are 'gzip', 'bz2', 'xz',\r\n",
      "            only used when the first argument is a filename\r\n",
      "        line_terminator : string, default ``'\\n'``\r\n",
      "            The newline character or character sequence to use in the output\r\n",
      "            file\r\n",
      "        quoting : optional constant from csv module\r\n",
      "            defaults to csv.QUOTE_MINIMAL. If you have set a `float_format`\r\n",
      "            then floats are converted to strings and thus csv.QUOTE_NONNUMERIC\r\n",
      "            will treat them as non-numeric\r\n",
      "        quotechar : string (length 1), default '\\\"'\r\n",
      "            character used to quote fields\r\n",
      "        doublequote : boolean, default True\r\n",
      "            Control quoting of `quotechar` inside a field\r\n",
      "        escapechar : string (length 1), default None\r\n",
      "            character used to escape `sep` and `quotechar` when appropriate\r\n",
      "        chunksize : int or None\r\n",
      "            rows to write at a time\r\n",
      "        tupleize_cols : boolean, default False\r\n",
      "            .. deprecated:: 0.21.0\r\n",
      "               This argument will be removed and will always write each row\r\n",
      "               of the multi-index as a separate row in the CSV file.\r\n",
      "\r\n",
      "            Write MultiIndex columns as a list of tuples (if True) or in\r\n",
      "            the new, expanded format, where each MultiIndex column is a row\r\n",
      "            in the CSV (if False).\r\n",
      "        date_format : string, default None\r\n",
      "            Format string for datetime objects\r\n",
      "        decimal: string, default '.'\r\n",
      "            Character recognized as decimal separator. E.g. use ',' for\r\n",
      "            European data\r\n",
      "\r\n",
      "        \"\"\"\r\n",
      "\r\n",
      "        if tupleize_cols is not None:\r\n",
      "            warnings.warn(\"The 'tupleize_cols' parameter is deprecated and \"\r\n",
      "                          \"will be removed in a future version\",\r\n",
      "                          FutureWarning, stacklevel=2)\r\n",
      "        else:\r\n",
      "            tupleize_cols = False\r\n",
      "\r\n",
      "        formatter = fmt.CSVFormatter(self, path_or_buf,\r\n",
      "                                     line_terminator=line_terminator, sep=sep,\r\n",
      "                                     encoding=encoding,\r\n",
      "                                     compression=compression, quoting=quoting,\r\n",
      "                                     na_rep=na_rep, float_format=float_format,\r\n",
      "                                     cols=columns, header=header, index=index,\r\n",
      "                                     index_label=index_label, mode=mode,\r\n",
      "                                     chunksize=chunksize, quotechar=quotechar,\r\n",
      "                                     tupleize_cols=tupleize_cols,\r\n",
      "                                     date_format=date_format,\r\n",
      "                                     doublequote=doublequote,\r\n",
      "                                     escapechar=escapechar, decimal=decimal)\r\n",
      "        formatter.save()\r\n",
      "\r\n",
      "        if path_or_buf is None:\r\n",
      "            return formatter.path_or_buf.getvalue()\r\n",
      "\r\n",
      "    @Appender(_shared_docs['to_excel'] % _shared_doc_kwargs)\r\n",
      "    def to_excel(self, excel_writer, sheet_name='Sheet1', na_rep='',\r\n",
      "                 float_format=None, columns=None, header=True, index=True,\r\n",
      "                 index_label=None, startrow=0, startcol=0, engine=None,\r\n",
      "                 merge_cells=True, encoding=None, inf_rep='inf', verbose=True,\r\n",
      "                 freeze_panes=None):\r\n",
      "\r\n",
      "        from pandas.io.formats.excel import ExcelFormatter\r\n",
      "        formatter = ExcelFormatter(self, na_rep=na_rep, cols=columns,\r\n",
      "                                   header=header,\r\n",
      "                                   float_format=float_format, index=index,\r\n",
      "                                   index_label=index_label,\r\n",
      "                                   merge_cells=merge_cells,\r\n",
      "                                   inf_rep=inf_rep)\r\n",
      "        formatter.write(excel_writer, sheet_name=sheet_name, startrow=startrow,\r\n",
      "                        startcol=startcol, freeze_panes=freeze_panes,\r\n",
      "                        engine=engine)\r\n",
      "\r\n",
      "    def to_stata(self, fname, convert_dates=None, write_index=True,\r\n",
      "                 encoding=\"latin-1\", byteorder=None, time_stamp=None,\r\n",
      "                 data_label=None, variable_labels=None):\r\n",
      "        \"\"\"\r\n",
      "        A class for writing Stata binary dta files from array-like objects\r\n",
      "\r\n",
      "        Parameters\r\n",
      "        ----------\r\n",
      "        fname : str or buffer\r\n",
      "            String path of file-like object\r\n",
      "        convert_dates : dict\r\n",
      "            Dictionary mapping columns containing datetime types to stata\r\n",
      "            internal format to use when wirting the dates. Options are 'tc',\r\n",
      "            'td', 'tm', 'tw', 'th', 'tq', 'ty'. Column can be either an integer\r\n",
      "            or a name. Datetime columns that do not have a conversion type\r\n",
      "            specified will be converted to 'tc'. Raises NotImplementedError if\r\n",
      "            a datetime column has timezone information\r\n",
      "        write_index : bool\r\n",
      "            Write the index to Stata dataset.\r\n",
      "        encoding : str\r\n",
      "            Default is latin-1. Unicode is not supported\r\n",
      "        byteorder : str\r\n",
      "            Can be \">\", \"<\", \"little\", or \"big\". default is `sys.byteorder`\r\n",
      "        time_stamp : datetime\r\n",
      "            A datetime to use as file creation date.  Default is the current\r\n",
      "            time.\r\n",
      "        dataset_label : str\r\n",
      "            A label for the data set.  Must be 80 characters or smaller.\r\n",
      "        variable_labels : dict\r\n",
      "            Dictionary containing columns as keys and variable labels as\r\n",
      "            values. Each label must be 80 characters or smaller.\r\n",
      "\r\n",
      "            .. versionadded:: 0.19.0\r\n",
      "\r\n",
      "        Raises\r\n",
      "        ------\r\n",
      "        NotImplementedError\r\n",
      "            * If datetimes contain timezone information\r\n",
      "            * Column dtype is not representable in Stata\r\n",
      "        ValueError\r\n",
      "            * Columns listed in convert_dates are noth either datetime64[ns]\r\n",
      "              or datetime.datetime\r\n",
      "            * Column listed in convert_dates is not in DataFrame\r\n",
      "            * Categorical label contains more than 32,000 characters\r\n",
      "\r\n",
      "            .. versionadded:: 0.19.0\r\n",
      "\r\n",
      "        Examples\r\n",
      "        --------\r\n",
      "        >>> writer = StataWriter('./data_file.dta', data)\r\n",
      "        >>> writer.write_file()\r\n",
      "\r\n",
      "        Or with dates\r\n",
      "\r\n",
      "        >>> writer = StataWriter('./date_data_file.dta', data, {2 : 'tw'})\r\n",
      "        >>> writer.write_file()\r\n",
      "        \"\"\"\r\n",
      "        from pandas.io.stata import StataWriter\r\n",
      "        writer = StataWriter(fname, self, convert_dates=convert_dates,\r\n",
      "                             encoding=encoding, byteorder=byteorder,\r\n",
      "                             time_stamp=time_stamp, data_label=data_label,\r\n",
      "                             write_index=write_index,\r\n",
      "                             variable_labels=variable_labels)\r\n",
      "        writer.write_file()\r\n",
      "\r\n",
      "    def to_feather(self, fname):\r\n",
      "        \"\"\"\r\n",
      "        write out the binary feather-format for DataFrames\r\n",
      "\r\n",
      "        .. versionadded:: 0.20.0\r\n",
      "\r\n",
      "        Parameters\r\n",
      "        ----------\r\n",
      "        fname : str\r\n",
      "            string file path\r\n",
      "\r\n",
      "        \"\"\"\r\n",
      "        from pandas.io.feather_format import to_feather\r\n",
      "        to_feather(self, fname)\r\n",
      "\r\n",
      "    def to_parquet(self, fname, engine='auto', compression='snappy',\r\n",
      "                   **kwargs):\r\n",
      "        \"\"\"\r\n",
      "        Write a DataFrame to the binary parquet format.\r\n",
      "\r\n",
      "        .. versionadded:: 0.21.0\r\n",
      "\r\n",
      "        Parameters\r\n",
      "        ----------\r\n",
      "        fname : str\r\n",
      "            string file path\r\n",
      "        engine : {'auto', 'pyarrow', 'fastparquet'}, default 'auto'\r\n",
      "            Parquet reader library to use. If 'auto', then the option\r\n",
      "            'io.parquet.engine' is used. If 'auto', then the first\r\n",
      "            library to be installed is used.\r\n",
      "        compression : str, optional, default 'snappy'\r\n",
      "            compression method, includes {'gzip', 'snappy', 'brotli'}\r\n",
      "        kwargs\r\n",
      "            Additional keyword arguments passed to the engine\r\n",
      "        \"\"\"\r\n",
      "        from pandas.io.parquet import to_parquet\r\n",
      "        to_parquet(self, fname, engine,\r\n",
      "                   compression=compression, **kwargs)\r\n",
      "\r\n",
      "    @Substitution(header='Write out the column names. If a list of strings '\r\n",
      "                         'is given, it is assumed to be aliases for the '\r\n",
      "                         'column names')\r\n",
      "    @Appender(fmt.docstring_to_string, indents=1)\r\n",
      "    def to_string(self, buf=None, columns=None, col_space=None, header=True,\r\n",
      "                  index=True, na_rep='NaN', formatters=None, float_format=None,\r\n",
      "                  sparsify=None, index_names=True, justify=None,\r\n",
      "                  line_width=None, max_rows=None, max_cols=None,\r\n",
      "                  show_dimensions=False):\r\n",
      "        \"\"\"\r\n",
      "        Render a DataFrame to a console-friendly tabular output.\r\n",
      "        \"\"\"\r\n",
      "\r\n",
      "        formatter = fmt.DataFrameFormatter(self, buf=buf, columns=columns,\r\n",
      "                                           col_space=col_space, na_rep=na_rep,\r\n",
      "                                           formatters=formatters,\r\n",
      "                                           float_format=float_format,\r\n",
      "                                           sparsify=sparsify, justify=justify,\r\n",
      "                                           index_names=index_names,\r\n",
      "                                           header=header, index=index,\r\n",
      "                                           line_width=line_width,\r\n",
      "                                           max_rows=max_rows,\r\n",
      "                                           max_cols=max_cols,\r\n",
      "                                           show_dimensions=show_dimensions)\r\n",
      "        formatter.to_string()\r\n",
      "\r\n",
      "        if buf is None:\r\n",
      "            result = formatter.buf.getvalue()\r\n",
      "            return result\r\n",
      "\r\n",
      "    @Substitution(header='whether to print column labels, default True')\r\n",
      "    @Appender(fmt.docstring_to_string, indents=1)\r\n",
      "    def to_html(self, buf=None, columns=None, col_space=None, header=True,\r\n",
      "                index=True, na_rep='NaN', formatters=None, float_format=None,\r\n",
      "                sparsify=None, index_names=True, justify=None, bold_rows=True,\r\n",
      "                classes=None, escape=True, max_rows=None, max_cols=None,\r\n",
      "                show_dimensions=False, notebook=False, decimal='.',\r\n",
      "                border=None):\r\n",
      "        \"\"\"\r\n",
      "        Render a DataFrame as an HTML table.\r\n",
      "\r\n",
      "        `to_html`-specific options:\r\n",
      "\r\n",
      "        bold_rows : boolean, default True\r\n",
      "            Make the row labels bold in the output\r\n",
      "        classes : str or list or tuple, default None\r\n",
      "            CSS class(es) to apply to the resulting html table\r\n",
      "        escape : boolean, default True\r\n",
      "            Convert the characters <, >, and & to HTML-safe sequences.=\r\n",
      "        max_rows : int, optional\r\n",
      "            Maximum number of rows to show before truncating. If None, show\r\n",
      "            all.\r\n",
      "        max_cols : int, optional\r\n",
      "            Maximum number of columns to show before truncating. If None, show\r\n",
      "            all.\r\n",
      "        decimal : string, default '.'\r\n",
      "            Character recognized as decimal separator, e.g. ',' in Europe\r\n",
      "\r\n",
      "            .. versionadded:: 0.18.0\r\n",
      "        border : int\r\n",
      "            A ``border=border`` attribute is included in the opening\r\n",
      "            `<table>` tag. Default ``pd.options.html.border``.\r\n",
      "\r\n",
      "            .. versionadded:: 0.19.0\r\n",
      "        \"\"\"\r\n",
      "\r\n",
      "        if (justify is not None and\r\n",
      "                justify not in fmt._VALID_JUSTIFY_PARAMETERS):\r\n",
      "            raise ValueError(\"Invalid value for justify parameter\")\r\n",
      "\r\n",
      "        formatter = fmt.DataFrameFormatter(self, buf=buf, columns=columns,\r\n",
      "                                           col_space=col_space, na_rep=na_rep,\r\n",
      "                                           formatters=formatters,\r\n",
      "                                           float_format=float_format,\r\n",
      "                                           sparsify=sparsify, justify=justify,\r\n",
      "                                           index_names=index_names,\r\n",
      "                                           header=header, index=index,\r\n",
      "                                           bold_rows=bold_rows, escape=escape,\r\n",
      "                                           max_rows=max_rows,\r\n",
      "                                           max_cols=max_cols,\r\n",
      "                                           show_dimensions=show_dimensions,\r\n",
      "                                           decimal=decimal)\r\n",
      "        # TODO: a generic formatter wld b in DataFrameFormatter\r\n",
      "        formatter.to_html(classes=classes, notebook=notebook, border=border)\r\n",
      "\r\n",
      "        if buf is None:\r\n",
      "            return formatter.buf.getvalue()\r\n",
      "\r\n",
      "    def info(self, verbose=None, buf=None, max_cols=None, memory_usage=None,\r\n",
      "             null_counts=None):\r\n",
      "        \"\"\"\r\n",
      "        Concise summary of a DataFrame.\r\n",
      "\r\n",
      "        Parameters\r\n",
      "        ----------\r\n",
      "        verbose : {None, True, False}, optional\r\n",
      "            Whether to print the full summary.\r\n",
      "            None follows the `display.max_info_columns` setting.\r\n",
      "            True or False overrides the `display.max_info_columns` setting.\r\n",
      "        buf : writable buffer, defaults to sys.stdout\r\n",
      "        max_cols : int, default None\r\n",
      "            Determines whether full summary or short summary is printed.\r\n",
      "            None follows the `display.max_info_columns` setting.\r\n",
      "        memory_usage : boolean/string, default None\r\n",
      "            Specifies whether total memory usage of the DataFrame\r\n",
      "            elements (including index) should be displayed. None follows\r\n",
      "            the `display.memory_usage` setting. True or False overrides\r\n",
      "            the `display.memory_usage` setting. A value of 'deep' is equivalent\r\n",
      "            of True, with deep introspection. Memory usage is shown in\r\n",
      "            human-readable units (base-2 representation).\r\n",
      "        null_counts : boolean, default None\r\n",
      "            Whether to show the non-null counts\r\n",
      "\r\n",
      "            - If None, then only show if the frame is smaller than\r\n",
      "              max_info_rows and max_info_columns.\r\n",
      "            - If True, always show counts.\r\n",
      "            - If False, never show counts.\r\n",
      "\r\n",
      "        \"\"\"\r\n",
      "        from pandas.io.formats.format import _put_lines\r\n",
      "\r\n",
      "        if buf is None:  # pragma: no cover\r\n",
      "            buf = sys.stdout\r",
      "\r\n",
      "\r\n",
      "        lines = []\r\n",
      "\r\n",
      "        lines.append(str(type(self)))\r\n",
      "        lines.append(self.index.summary())\r\n",
      "\r\n",
      "        if len(self.columns) == 0:\r\n",
      "            lines.append('Empty %s' % type(self).__name__)\r\n",
      "            _put_lines(buf, lines)\r\n",
      "            return\r\n",
      "\r\n",
      "        cols = self.columns\r\n",
      "\r\n",
      "        # hack\r\n",
      "        if max_cols is None:\r\n",
      "            max_cols = get_option('display.max_info_columns',\r\n",
      "                                  len(self.columns) + 1)\r\n",
      "\r\n",
      "        max_rows = get_option('display.max_info_rows', len(self) + 1)\r\n",
      "\r\n",
      "        if null_counts is None:\r\n",
      "            show_counts = ((len(self.columns) <= max_cols) and\r\n",
      "                           (len(self) < max_rows))\r\n",
      "        else:\r\n",
      "            show_counts = null_counts\r\n",
      "        exceeds_info_cols = len(self.columns) > max_cols\r\n",
      "\r\n",
      "        def _verbose_repr():\r\n",
      "            lines.append('Data columns (total %d columns):' %\r\n",
      "                         len(self.columns))\r\n",
      "            space = max([len(pprint_thing(k)) for k in self.columns]) + 4\r\n",
      "            counts = None\r\n",
      "\r\n",
      "            tmpl = \"%s%s\"\r\n",
      "            if show_counts:\r\n",
      "                counts = self.count()\r\n",
      "                if len(cols) != len(counts):  # pragma: no cover\r\n",
      "                    raise AssertionError('Columns must equal counts (%d != %d)'\r\n",
      "                                         % (len(cols), len(counts)))\r\n",
      "                tmpl = \"%s non-null %s\"\r\n",
      "\r\n",
      "            dtypes = self.dtypes\r\n",
      "            for i, col in enumerate(self.columns):\r\n",
      "                dtype = dtypes.iloc[i]\r\n",
      "                col = pprint_thing(col)\r\n",
      "\r\n",
      "                count = \"\"\r\n",
      "                if show_counts:\r\n",
      "                    count = counts.iloc[i]\r\n",
      "\r\n",
      "                lines.append(_put_str(col, space) + tmpl % (count, dtype))\r\n",
      "\r\n",
      "        def _non_verbose_repr():\r\n",
      "            lines.append(self.columns.summary(name='Columns'))\r\n",
      "\r\n",
      "        def _sizeof_fmt(num, size_qualifier):\r\n",
      "            # returns size in human readable format\r\n",
      "            for x in ['bytes', 'KB', 'MB', 'GB', 'TB']:\r\n",
      "                if num < 1024.0:\r\n",
      "                    return \"%3.1f%s %s\" % (num, size_qualifier, x)\r\n",
      "                num /= 1024.0\r\n",
      "            return \"%3.1f%s %s\" % (num, size_qualifier, 'PB')\r\n",
      "\r\n",
      "        if verbose:\r\n",
      "            _verbose_repr()\r\n",
      "        elif verbose is False:  # specifically set to False, not nesc None\r\n",
      "            _non_verbose_repr()\r\n",
      "        else:\r\n",
      "            if exceeds_info_cols:\r\n",
      "                _non_verbose_repr()\r\n",
      "            else:\r\n",
      "                _verbose_repr()\r\n",
      "\r\n",
      "        counts = self.get_dtype_counts()\r\n",
      "        dtypes = ['%s(%d)' % k for k in sorted(compat.iteritems(counts))]\r\n",
      "        lines.append('dtypes: %s' % ', '.join(dtypes))\r\n",
      "\r\n",
      "        if memory_usage is None:\r\n",
      "            memory_usage = get_option('display.memory_usage')\r\n",
      "        if memory_usage:\r\n",
      "            # append memory usage of df to display\r\n",
      "            size_qualifier = ''\r\n",
      "            if memory_usage == 'deep':\r\n",
      "                deep = True\r\n",
      "            else:\r\n",
      "                # size_qualifier is just a best effort; not guaranteed to catch\r\n",
      "                # all cases (e.g., it misses categorical data even with object\r\n",
      "                # categories)\r\n",
      "                deep = False\r\n",
      "                if ('object' in counts or\r\n",
      "                        self.index._is_memory_usage_qualified()):\r\n",
      "                    size_qualifier = '+'\r\n",
      "            mem_usage = self.memory_usage(index=True, deep=deep).sum()\r\n",
      "            lines.append(\"memory usage: %s\\n\" %\r\n",
      "                         _sizeof_fmt(mem_usage, size_qualifier))\r\n",
      "        _put_lines(buf, lines)\r\n",
      "\r\n",
      "    def memory_usage(self, index=True, deep=False):\r\n",
      "        \"\"\"Memory usage of DataFrame columns.\r\n",
      "\r\n",
      "        Parameters\r\n",
      "        ----------\r\n",
      "        index : bool\r\n",
      "            Specifies whether to include memory usage of DataFrame's\r\n",
      "            index in returned Series. If `index=True` (default is False)\r\n",
      "            the first index of the Series is `Index`.\r\n",
      "        deep : bool\r\n",
      "            Introspect the data deeply, interrogate\r\n",
      "            `object` dtypes for system-level memory consumption\r\n",
      "\r\n",
      "        Returns\r\n",
      "        -------\r\n",
      "        sizes : Series\r\n",
      "            A series with column names as index and memory usage of\r\n",
      "            columns with units of bytes.\r\n",
      "\r\n",
      "        Notes\r\n",
      "        -----\r\n",
      "        Memory usage does not include memory consumed by elements that\r\n",
      "        are not components of the array if deep=False\r\n",
      "\r\n",
      "        See Also\r\n",
      "        --------\r\n",
      "        numpy.ndarray.nbytes\r\n",
      "        \"\"\"\r\n",
      "        result = Series([c.memory_usage(index=False, deep=deep)\r\n",
      "                         for col, c in self.iteritems()], index=self.columns)\r\n",
      "        if index:\r\n",
      "            result = Series(self.index.memory_usage(deep=deep),\r\n",
      "                            index=['Index']).append(result)\r\n",
      "        return result\r\n",
      "\r\n",
      "    def transpose(self, *args, **kwargs):\r\n",
      "        \"\"\"Transpose index and columns\"\"\"\r\n",
      "        nv.validate_transpose(args, dict())\r\n",
      "        return super(DataFrame, self).transpose(1, 0, **kwargs)\r\n",
      "\r\n",
      "    T = property(transpose)\r\n",
      "\r\n",
      "    # ----------------------------------------------------------------------\r\n",
      "    # Picklability\r\n",
      "\r\n",
      "    # legacy pickle formats\r\n",
      "    def _unpickle_frame_compat(self, state):  # pragma: no cover\r\n",
      "        from pandas.core.common import _unpickle_array\r\n",
      "        if len(state) == 2:  # pragma: no cover\r\n",
      "            series, idx = state\r\n",
      "            columns = sorted(series)\r\n",
      "        else:\r\n",
      "            series, cols, idx = state\r\n",
      "            columns = _unpickle_array(cols)\r\n",
      "\r\n",
      "        index = _unpickle_array(idx)\r\n",
      "        self._data = self._init_dict(series, index, columns, None)\r\n",
      "\r\n",
      "    def _unpickle_matrix_compat(self, state):  # pragma: no cover\r\n",
      "        from pandas.core.common import _unpickle_array\r\n",
      "        # old unpickling\r\n",
      "        (vals, idx, cols), object_state = state\r\n",
      "\r\n",
      "        index = _unpickle_array(idx)\r\n",
      "        dm = DataFrame(vals, index=index, columns=_unpickle_array(cols),\r\n",
      "                       copy=False)\r\n",
      "\r\n",
      "        if object_state is not None:\r\n",
      "            ovals, _, ocols = object_state\r\n",
      "            objects = DataFrame(ovals, index=index,\r\n",
      "                                columns=_unpickle_array(ocols), copy=False)\r\n",
      "\r\n",
      "            dm = dm.join(objects)\r\n",
      "\r\n",
      "        self._data = dm._data\r\n",
      "\r\n",
      "    # ----------------------------------------------------------------------\r\n",
      "    # Getting and setting elements\r\n",
      "\r\n",
      "    def get_value(self, index, col, takeable=False):\r\n",
      "        \"\"\"\r\n",
      "        Quickly retrieve single value at passed column and index\r\n",
      "\r\n",
      "        .. deprecated:: 0.21.0\r\n",
      "\r\n",
      "        Please use .at[] or .iat[] accessors.\r\n",
      "\r\n",
      "        Parameters\r\n",
      "        ----------\r\n",
      "        index : row label\r\n",
      "        col : column label\r\n",
      "        takeable : interpret the index/col as indexers, default False\r\n",
      "\r\n",
      "        Returns\r\n",
      "        -------\r\n",
      "        value : scalar value\r\n",
      "        \"\"\"\r\n",
      "\r\n",
      "        warnings.warn(\"get_value is deprecated and will be removed \"\r\n",
      "                      \"in a future release. Please use \"\r\n",
      "                      \".at[] or .iat[] accessors instead\", FutureWarning,\r\n",
      "                      stacklevel=2)\r\n",
      "        return self._get_value(index, col, takeable=takeable)\r\n",
      "\r\n",
      "    def _get_value(self, index, col, takeable=False):\r\n",
      "\r\n",
      "        if takeable:\r\n",
      "            series = self._iget_item_cache(col)\r\n",
      "            return _maybe_box_datetimelike(series._values[index])\r\n",
      "\r\n",
      "        series = self._get_item_cache(col)\r\n",
      "        engine = self.index._engine\r\n",
      "\r\n",
      "        try:\r\n",
      "            return engine.get_value(series._values, index)\r\n",
      "        except (TypeError, ValueError):\r\n",
      "\r\n",
      "            # we cannot handle direct indexing\r\n",
      "            # use positional\r\n",
      "            col = self.columns.get_loc(col)\r\n",
      "            index = self.index.get_loc(index)\r\n",
      "            return self._get_value(index, col, takeable=True)\r\n",
      "    _get_value.__doc__ = get_value.__doc__\r\n",
      "\r\n",
      "    def set_value(self, index, col, value, takeable=False):\r\n",
      "        \"\"\"\r\n",
      "        Put single value at passed column and index\r\n",
      "\r\n",
      "        .. deprecated:: 0.21.0\r\n",
      "\r\n",
      "        Please use .at[] or .iat[] accessors.\r\n",
      "\r\n",
      "        Parameters\r\n",
      "        ----------\r\n",
      "        index : row label\r\n",
      "        col : column label\r\n",
      "        value : scalar value\r\n",
      "        takeable : interpret the index/col as indexers, default False\r\n",
      "\r\n",
      "        Returns\r\n",
      "        -------\r\n",
      "        frame : DataFrame\r\n",
      "            If label pair is contained, will be reference to calling DataFrame,\r\n",
      "            otherwise a new object\r\n",
      "        \"\"\"\r\n",
      "        warnings.warn(\"set_value is deprecated and will be removed \"\r\n",
      "                      \"in a future release. Please use \"\r\n",
      "                      \".at[] or .iat[] accessors instead\", FutureWarning,\r\n",
      "                      stacklevel=2)\r\n",
      "        return self._set_value(index, col, value, takeable=takeable)\r\n",
      "\r\n",
      "    def _set_value(self, index, col, value, takeable=False):\r\n",
      "        try:\r\n",
      "            if takeable is True:\r\n",
      "                series = self._iget_item_cache(col)\r\n",
      "                return series._set_value(index, value, takeable=True)\r\n",
      "\r\n",
      "            series = self._get_item_cache(col)\r\n",
      "            engine = self.index._engine\r\n",
      "            engine.set_value(series._values, index, value)\r\n",
      "            return self\r\n",
      "        except (KeyError, TypeError):\r\n",
      "\r\n",
      "            # set using a non-recursive method & reset the cache\r\n",
      "            self.loc[index, col] = value\r\n",
      "            self._item_cache.pop(col, None)\r\n",
      "\r\n",
      "            return self\r\n",
      "    _set_value.__doc__ = set_value.__doc__\r\n",
      "\r\n",
      "    def _ixs(self, i, axis=0):\r\n",
      "        \"\"\"\r\n",
      "        i : int, slice, or sequence of integers\r\n",
      "        axis : int\r\n",
      "        \"\"\"\r\n",
      "\r\n",
      "        # irow\r\n",
      "        if axis == 0:\r\n",
      "            \"\"\"\r\n",
      "            Notes\r\n",
      "            -----\r\n",
      "            If slice passed, the resulting data will be a view\r\n",
      "            \"\"\"\r\n",
      "\r\n",
      "            if isinstance(i, slice):\r\n",
      "                return self[i]\r\n",
      "            else:\r\n",
      "                label = self.index[i]\r\n",
      "                if isinstance(label, Index):\r\n",
      "                    # a location index by definition\r\n",
      "                    result = self.take(i, axis=axis)\r\n",
      "                    copy = True\r\n",
      "                else:\r\n",
      "                    new_values = self._data.fast_xs(i)\r\n",
      "                    if is_scalar(new_values):\r\n",
      "                        return new_values\r\n",
      "\r\n",
      "                    # if we are a copy, mark as such\r",
      "\r\n",
      "                    copy = (isinstance(new_values, np.ndarray) and\r\n",
      "                            new_values.base is None)\r\n",
      "                    result = self._constructor_sliced(new_values,\r\n",
      "                                                      index=self.columns,\r\n",
      "                                                      name=self.index[i],\r\n",
      "                                                      dtype=new_values.dtype)\r\n",
      "                result._set_is_copy(self, copy=copy)\r\n",
      "                return result\r\n",
      "\r\n",
      "        # icol\r\n",
      "        else:\r\n",
      "            \"\"\"\r\n",
      "            Notes\r\n",
      "            -----\r\n",
      "            If slice passed, the resulting data will be a view\r\n",
      "            \"\"\"\r\n",
      "\r\n",
      "            label = self.columns[i]\r\n",
      "            if isinstance(i, slice):\r\n",
      "                # need to return view\r\n",
      "                lab_slice = slice(label[0], label[-1])\r\n",
      "                return self.loc[:, lab_slice]\r\n",
      "            else:\r\n",
      "                if isinstance(label, Index):\r\n",
      "                    return self._take(i, axis=1, convert=True)\r\n",
      "\r\n",
      "                index_len = len(self.index)\r\n",
      "\r\n",
      "                # if the values returned are not the same length\r\n",
      "                # as the index (iow a not found value), iget returns\r\n",
      "                # a 0-len ndarray. This is effectively catching\r\n",
      "                # a numpy error (as numpy should really raise)\r\n",
      "                values = self._data.iget(i)\r\n",
      "\r\n",
      "                if index_len and not len(values):\r\n",
      "                    values = np.array([np.nan] * index_len, dtype=object)\r\n",
      "                result = self._constructor_sliced.from_array(values,\r\n",
      "                                                             index=self.index,\r\n",
      "                                                             name=label,\r\n",
      "                                                             fastpath=True)\r\n",
      "\r\n",
      "                # this is a cached value, mark it so\r\n",
      "                result._set_as_cached(label, self)\r\n",
      "\r\n",
      "                return result\r\n",
      "\r\n",
      "    def __getitem__(self, key):\r\n",
      "        key = com._apply_if_callable(key, self)\r\n",
      "\r\n",
      "        # shortcut if we are an actual column\r\n",
      "        is_mi_columns = isinstance(self.columns, MultiIndex)\r\n",
      "        try:\r\n",
      "            if key in self.columns and not is_mi_columns:\r\n",
      "                return self._getitem_column(key)\r\n",
      "        except:\r\n",
      "            pass\r\n",
      "\r\n",
      "        # see if we can slice the rows\r\n",
      "        indexer = convert_to_index_sliceable(self, key)\r\n",
      "        if indexer is not None:\r\n",
      "            return self._getitem_slice(indexer)\r\n",
      "\r\n",
      "        if isinstance(key, (Series, np.ndarray, Index, list)):\r\n",
      "            # either boolean or fancy integer index\r\n",
      "            return self._getitem_array(key)\r\n",
      "        elif isinstance(key, DataFrame):\r\n",
      "            return self._getitem_frame(key)\r\n",
      "        elif is_mi_columns:\r\n",
      "            return self._getitem_multilevel(key)\r\n",
      "        else:\r\n",
      "            return self._getitem_column(key)\r\n",
      "\r\n",
      "    def _getitem_column(self, key):\r\n",
      "        \"\"\" return the actual column \"\"\"\r\n",
      "\r\n",
      "        # get column\r\n",
      "        if self.columns.is_unique:\r\n",
      "            return self._get_item_cache(key)\r\n",
      "\r\n",
      "        # duplicate columns & possible reduce dimensionality\r\n",
      "        result = self._constructor(self._data.get(key))\r\n",
      "        if result.columns.is_unique:\r\n",
      "            result = result[key]\r\n",
      "\r\n",
      "        return result\r\n",
      "\r\n",
      "    def _getitem_slice(self, key):\r\n",
      "        return self._slice(key, axis=0)\r\n",
      "\r\n",
      "    def _getitem_array(self, key):\r\n",
      "        # also raises Exception if object array with NA values\r\n",
      "        if com.is_bool_indexer(key):\r\n",
      "            # warning here just in case -- previously __setitem__ was\r\n",
      "            # reindexing but __getitem__ was not; it seems more reasonable to\r\n",
      "            # go with the __setitem__ behavior since that is more consistent\r\n",
      "            # with all other indexing behavior\r\n",
      "            if isinstance(key, Series) and not key.index.equals(self.index):\r\n",
      "                warnings.warn(\"Boolean Series key will be reindexed to match \"\r\n",
      "                              \"DataFrame index.\", UserWarning, stacklevel=3)\r\n",
      "            elif len(key) != len(self.index):\r\n",
      "                raise ValueError('Item wrong length %d instead of %d.' %\r\n",
      "                                 (len(key), len(self.index)))\r\n",
      "            # check_bool_indexer will throw exception if Series key cannot\r\n",
      "            # be reindexed to match DataFrame rows\r\n",
      "            key = check_bool_indexer(self.index, key)\r\n",
      "            indexer = key.nonzero()[0]\r\n",
      "            return self._take(indexer, axis=0, convert=False)\r\n",
      "        else:\r\n",
      "            indexer = self.loc._convert_to_indexer(key, axis=1)\r\n",
      "            return self._take(indexer, axis=1, convert=True)\r\n",
      "\r\n",
      "    def _getitem_multilevel(self, key):\r\n",
      "        loc = self.columns.get_loc(key)\r\n",
      "        if isinstance(loc, (slice, Series, np.ndarray, Index)):\r\n",
      "            new_columns = self.columns[loc]\r\n",
      "            result_columns = maybe_droplevels(new_columns, key)\r\n",
      "            if self._is_mixed_type:\r\n",
      "                result = self.reindex(columns=new_columns)\r\n",
      "                result.columns = result_columns\r\n",
      "            else:\r\n",
      "                new_values = self.values[:, loc]\r\n",
      "                result = self._constructor(new_values, index=self.index,\r\n",
      "                                           columns=result_columns)\r\n",
      "                result = result.__finalize__(self)\r\n",
      "\r\n",
      "            # If there is only one column being returned, and its name is\r\n",
      "            # either an empty string, or a tuple with an empty string as its\r\n",
      "            # first element, then treat the empty string as a placeholder\r\n",
      "            # and return the column as if the user had provided that empty\r\n",
      "            # string in the key. If the result is a Series, exclude the\r\n",
      "            # implied empty string from its name.\r\n",
      "            if len(result.columns) == 1:\r\n",
      "                top = result.columns[0]\r\n",
      "                if isinstance(top, tuple):\r\n",
      "                    top = top[0]\r\n",
      "                if top == '':\r\n",
      "                    result = result['']\r\n",
      "                    if isinstance(result, Series):\r\n",
      "                        result = self._constructor_sliced(result,\r\n",
      "                                                          index=self.index,\r\n",
      "                                                          name=key)\r\n",
      "\r\n",
      "            result._set_is_copy(self)\r\n",
      "            return result\r\n",
      "        else:\r\n",
      "            return self._get_item_cache(key)\r\n",
      "\r\n",
      "    def _getitem_frame(self, key):\r\n",
      "        if key.values.size and not is_bool_dtype(key.values):\r\n",
      "            raise ValueError('Must pass DataFrame with boolean values only')\r\n",
      "        return self.where(key)\r\n",
      "\r\n",
      "    def query(self, expr, inplace=False, **kwargs):\r\n",
      "        \"\"\"Query the columns of a frame with a boolean expression.\r\n",
      "\r\n",
      "        Parameters\r\n",
      "        ----------\r\n",
      "        expr : string\r\n",
      "            The query string to evaluate.  You can refer to variables\r\n",
      "            in the environment by prefixing them with an '@' character like\r\n",
      "            ``@a + b``.\r\n",
      "        inplace : bool\r\n",
      "            Whether the query should modify the data in place or return\r\n",
      "            a modified copy\r\n",
      "\r\n",
      "            .. versionadded:: 0.18.0\r\n",
      "\r\n",
      "        kwargs : dict\r\n",
      "            See the documentation for :func:`pandas.eval` for complete details\r\n",
      "            on the keyword arguments accepted by :meth:`DataFrame.query`.\r\n",
      "\r\n",
      "        Returns\r\n",
      "        -------\r\n",
      "        q : DataFrame\r\n",
      "\r\n",
      "        Notes\r\n",
      "        -----\r\n",
      "        The result of the evaluation of this expression is first passed to\r\n",
      "        :attr:`DataFrame.loc` and if that fails because of a\r\n",
      "        multidimensional key (e.g., a DataFrame) then the result will be passed\r\n",
      "        to :meth:`DataFrame.__getitem__`.\r\n",
      "\r\n",
      "        This method uses the top-level :func:`pandas.eval` function to\r\n",
      "        evaluate the passed query.\r\n",
      "\r\n",
      "        The :meth:`~pandas.DataFrame.query` method uses a slightly\r\n",
      "        modified Python syntax by default. For example, the ``&`` and ``|``\r\n",
      "        (bitwise) operators have the precedence of their boolean cousins,\r\n",
      "        :keyword:`and` and :keyword:`or`. This *is* syntactically valid Python,\r\n",
      "        however the semantics are different.\r\n",
      "\r\n",
      "        You can change the semantics of the expression by passing the keyword\r\n",
      "        argument ``parser='python'``. This enforces the same semantics as\r\n",
      "        evaluation in Python space. Likewise, you can pass ``engine='python'``\r\n",
      "        to evaluate an expression using Python itself as a backend. This is not\r\n",
      "        recommended as it is inefficient compared to using ``numexpr`` as the\r\n",
      "        engine.\r\n",
      "\r\n",
      "        The :attr:`DataFrame.index` and\r\n",
      "        :attr:`DataFrame.columns` attributes of the\r\n",
      "        :class:`~pandas.DataFrame` instance are placed in the query namespace\r\n",
      "        by default, which allows you to treat both the index and columns of the\r\n",
      "        frame as a column in the frame.\r\n",
      "        The identifier ``index`` is used for the frame index; you can also\r\n",
      "        use the name of the index to identify it in a query.\r\n",
      "\r\n",
      "        For further details and examples see the ``query`` documentation in\r\n",
      "        :ref:`indexing <indexing.query>`.\r\n",
      "\r\n",
      "        See Also\r\n",
      "        --------\r\n",
      "        pandas.eval\r\n",
      "        DataFrame.eval\r\n",
      "\r\n",
      "        Examples\r\n",
      "        --------\r\n",
      "        >>> from numpy.random import randn\r\n",
      "        >>> from pandas import DataFrame\r\n",
      "        >>> df = DataFrame(randn(10, 2), columns=list('ab'))\r\n",
      "        >>> df.query('a > b')\r\n",
      "        >>> df[df.a > df.b]  # same result as the previous expression\r\n",
      "        \"\"\"\r\n",
      "        inplace = validate_bool_kwarg(inplace, 'inplace')\r\n",
      "        if not isinstance(expr, compat.string_types):\r\n",
      "            msg = \"expr must be a string to be evaluated, {0} given\"\r\n",
      "            raise ValueError(msg.format(type(expr)))\r\n",
      "        kwargs['level'] = kwargs.pop('level', 0) + 1\r\n",
      "        kwargs['target'] = None\r\n",
      "        res = self.eval(expr, **kwargs)\r\n",
      "\r\n",
      "        try:\r\n",
      "            new_data = self.loc[res]\r\n",
      "        except ValueError:\r\n",
      "            # when res is multi-dimensional loc raises, but this is sometimes a\r\n",
      "            # valid query\r\n",
      "            new_data = self[res]\r\n",
      "\r\n",
      "        if inplace:\r\n",
      "            self._update_inplace(new_data)\r\n",
      "        else:\r\n",
      "            return new_data\r\n",
      "\r\n",
      "    def eval(self, expr, inplace=False, **kwargs):\r\n",
      "        \"\"\"Evaluate an expression in the context of the calling DataFrame\r\n",
      "        instance.\r\n",
      "\r\n",
      "        Parameters\r\n",
      "        ----------\r\n",
      "        expr : string\r\n",
      "            The expression string to evaluate.\r\n",
      "        inplace : bool, default False\r\n",
      "            If the expression contains an assignment, whether to perform the\r\n",
      "            operation inplace and mutate the existing DataFrame. Otherwise,\r\n",
      "            a new DataFrame is returned.\r\n",
      "\r\n",
      "            .. versionadded:: 0.18.0\r\n",
      "\r\n",
      "        kwargs : dict\r\n",
      "            See the documentation for :func:`~pandas.eval` for complete details\r\n",
      "            on the keyword arguments accepted by\r\n",
      "            :meth:`~pandas.DataFrame.query`.\r\n",
      "\r\n",
      "        Returns\r\n",
      "        -------\r\n",
      "        ret : ndarray, scalar, or pandas object\r\n",
      "\r\n",
      "        See Also\r\n",
      "        --------\r\n",
      "        pandas.DataFrame.query\r\n",
      "        pandas.DataFrame.assign\r\n",
      "        pandas.eval\r\n",
      "\r\n",
      "        Notes\r\n",
      "        -----\r\n",
      "        For more details see the API documentation for :func:`~pandas.eval`.\r\n",
      "        For detailed examples see :ref:`enhancing performance with eval\r",
      "\r\n",
      "        <enhancingperf.eval>`.\r\n",
      "\r\n",
      "        Examples\r\n",
      "        --------\r\n",
      "        >>> from numpy.random import randn\r\n",
      "        >>> from pandas import DataFrame\r\n",
      "        >>> df = DataFrame(randn(10, 2), columns=list('ab'))\r\n",
      "        >>> df.eval('a + b')\r\n",
      "        >>> df.eval('c = a + b')\r\n",
      "        \"\"\"\r\n",
      "        from pandas.core.computation.eval import eval as _eval\r\n",
      "\r\n",
      "        inplace = validate_bool_kwarg(inplace, 'inplace')\r\n",
      "        resolvers = kwargs.pop('resolvers', None)\r\n",
      "        kwargs['level'] = kwargs.pop('level', 0) + 1\r\n",
      "        if resolvers is None:\r\n",
      "            index_resolvers = self._get_index_resolvers()\r\n",
      "            resolvers = dict(self.iteritems()), index_resolvers\r\n",
      "        if 'target' not in kwargs:\r\n",
      "            kwargs['target'] = self\r\n",
      "        kwargs['resolvers'] = kwargs.get('resolvers', ()) + tuple(resolvers)\r\n",
      "        return _eval(expr, inplace=inplace, **kwargs)\r\n",
      "\r\n",
      "    def select_dtypes(self, include=None, exclude=None):\r\n",
      "        \"\"\"Return a subset of a DataFrame including/excluding columns based on\r\n",
      "        their ``dtype``.\r\n",
      "\r\n",
      "        Parameters\r\n",
      "        ----------\r\n",
      "        include, exclude : scalar or list-like\r\n",
      "            A selection of dtypes or strings to be included/excluded. At least\r\n",
      "            one of these parameters must be supplied.\r\n",
      "\r\n",
      "        Raises\r\n",
      "        ------\r\n",
      "        ValueError\r\n",
      "            * If both of ``include`` and ``exclude`` are empty\r\n",
      "            * If ``include`` and ``exclude`` have overlapping elements\r\n",
      "            * If any kind of string dtype is passed in.\r\n",
      "\r\n",
      "        Returns\r\n",
      "        -------\r\n",
      "        subset : DataFrame\r\n",
      "            The subset of the frame including the dtypes in ``include`` and\r\n",
      "            excluding the dtypes in ``exclude``.\r\n",
      "\r\n",
      "        Notes\r\n",
      "        -----\r\n",
      "        * To select all *numeric* types use the numpy dtype ``numpy.number``\r\n",
      "        * To select strings you must use the ``object`` dtype, but note that\r\n",
      "          this will return *all* object dtype columns\r\n",
      "        * See the `numpy dtype hierarchy\r\n",
      "          <http://docs.scipy.org/doc/numpy/reference/arrays.scalars.html>`__\r\n",
      "        * To select datetimes, use np.datetime64, 'datetime' or 'datetime64'\r\n",
      "        * To select timedeltas, use np.timedelta64, 'timedelta' or\r\n",
      "          'timedelta64'\r\n",
      "        * To select Pandas categorical dtypes, use 'category'\r\n",
      "        * To select Pandas datetimetz dtypes, use 'datetimetz' (new in 0.20.0),\r\n",
      "          or a 'datetime64[ns, tz]' string\r\n",
      "\r\n",
      "        Examples\r\n",
      "        --------\r\n",
      "        >>> df = pd.DataFrame({'a': np.random.randn(6).astype('f4'),\r\n",
      "        ...                    'b': [True, False] * 3,\r\n",
      "        ...                    'c': [1.0, 2.0] * 3})\r\n",
      "        >>> df\r\n",
      "                a      b  c\r\n",
      "        0  0.3962   True  1\r\n",
      "        1  0.1459  False  2\r\n",
      "        2  0.2623   True  1\r\n",
      "        3  0.0764  False  2\r\n",
      "        4 -0.9703   True  1\r\n",
      "        5 -1.2094  False  2\r\n",
      "        >>> df.select_dtypes(include='bool')\r\n",
      "           c\r\n",
      "        0  True\r\n",
      "        1  False\r\n",
      "        2  True\r\n",
      "        3  False\r\n",
      "        4  True\r\n",
      "        5  False\r\n",
      "        >>> df.select_dtypes(include=['float64'])\r\n",
      "           c\r\n",
      "        0  1\r\n",
      "        1  2\r\n",
      "        2  1\r\n",
      "        3  2\r\n",
      "        4  1\r\n",
      "        5  2\r\n",
      "        >>> df.select_dtypes(exclude=['floating'])\r\n",
      "               b\r\n",
      "        0   True\r\n",
      "        1  False\r\n",
      "        2   True\r\n",
      "        3  False\r\n",
      "        4   True\r\n",
      "        5  False\r\n",
      "        \"\"\"\r\n",
      "\r\n",
      "        if not is_list_like(include):\r\n",
      "            include = (include,) if include is not None else ()\r\n",
      "        if not is_list_like(exclude):\r\n",
      "            exclude = (exclude,) if exclude is not None else ()\r\n",
      "\r\n",
      "        selection = tuple(map(frozenset, (include, exclude)))\r\n",
      "\r\n",
      "        if not any(selection):\r\n",
      "            raise ValueError('at least one of include or exclude must be '\r\n",
      "                             'nonempty')\r\n",
      "\r\n",
      "        # convert the myriad valid dtypes object to a single representation\r\n",
      "        include, exclude = map(\r\n",
      "            lambda x: frozenset(map(_get_dtype_from_object, x)), selection)\r\n",
      "        for dtypes in (include, exclude):\r\n",
      "            invalidate_string_dtypes(dtypes)\r\n",
      "\r\n",
      "        # can't both include AND exclude!\r\n",
      "        if not include.isdisjoint(exclude):\r\n",
      "            raise ValueError('include and exclude overlap on %s' %\r\n",
      "                             (include & exclude))\r\n",
      "\r\n",
      "        # empty include/exclude -> defaults to True\r\n",
      "        # three cases (we've already raised if both are empty)\r\n",
      "        # case 1: empty include, nonempty exclude\r\n",
      "        # we have True, True, ... True for include, same for exclude\r\n",
      "        # in the loop below we get the excluded\r\n",
      "        # and when we call '&' below we get only the excluded\r\n",
      "        # case 2: nonempty include, empty exclude\r\n",
      "        # same as case 1, but with include\r\n",
      "        # case 3: both nonempty\r\n",
      "        # the \"union\" of the logic of case 1 and case 2:\r\n",
      "        # we get the included and excluded, and return their logical and\r\n",
      "        include_these = Series(not bool(include), index=self.columns)\r\n",
      "        exclude_these = Series(not bool(exclude), index=self.columns)\r\n",
      "\r\n",
      "        def is_dtype_instance_mapper(column, dtype):\r\n",
      "            return column, functools.partial(issubclass, dtype.type)\r\n",
      "\r\n",
      "        for column, f in itertools.starmap(is_dtype_instance_mapper,\r\n",
      "                                           self.dtypes.iteritems()):\r\n",
      "            if include:  # checks for the case of empty include or exclude\r\n",
      "                include_these[column] = any(map(f, include))\r\n",
      "            if exclude:\r\n",
      "                exclude_these[column] = not any(map(f, exclude))\r\n",
      "\r\n",
      "        dtype_indexer = include_these & exclude_these\r\n",
      "        return self.loc[com._get_info_slice(self, dtype_indexer)]\r\n",
      "\r\n",
      "    def _box_item_values(self, key, values):\r\n",
      "        items = self.columns[self.columns.get_loc(key)]\r\n",
      "        if values.ndim == 2:\r\n",
      "            return self._constructor(values.T, columns=items, index=self.index)\r\n",
      "        else:\r\n",
      "            return self._box_col_values(values, items)\r\n",
      "\r\n",
      "    def _box_col_values(self, values, items):\r\n",
      "        \"\"\" provide boxed values for a column \"\"\"\r\n",
      "        return self._constructor_sliced.from_array(values, index=self.index,\r\n",
      "                                                   name=items, fastpath=True)\r\n",
      "\r\n",
      "    def __setitem__(self, key, value):\r\n",
      "        key = com._apply_if_callable(key, self)\r\n",
      "\r\n",
      "        # see if we can slice the rows\r\n",
      "        indexer = convert_to_index_sliceable(self, key)\r\n",
      "        if indexer is not None:\r\n",
      "            return self._setitem_slice(indexer, value)\r\n",
      "\r\n",
      "        if isinstance(key, (Series, np.ndarray, list, Index)):\r\n",
      "            self._setitem_array(key, value)\r\n",
      "        elif isinstance(key, DataFrame):\r\n",
      "            self._setitem_frame(key, value)\r\n",
      "        else:\r\n",
      "            # set column\r\n",
      "            self._set_item(key, value)\r\n",
      "\r\n",
      "    def _setitem_slice(self, key, value):\r\n",
      "        self._check_setitem_copy()\r\n",
      "        self.loc._setitem_with_indexer(key, value)\r\n",
      "\r\n",
      "    def _setitem_array(self, key, value):\r\n",
      "        # also raises Exception if object array with NA values\r\n",
      "        if com.is_bool_indexer(key):\r\n",
      "            if len(key) != len(self.index):\r\n",
      "                raise ValueError('Item wrong length %d instead of %d!' %\r\n",
      "                                 (len(key), len(self.index)))\r\n",
      "            key = check_bool_indexer(self.index, key)\r\n",
      "            indexer = key.nonzero()[0]\r\n",
      "            self._check_setitem_copy()\r\n",
      "            self.loc._setitem_with_indexer(indexer, value)\r\n",
      "        else:\r\n",
      "            if isinstance(value, DataFrame):\r\n",
      "                if len(value.columns) != len(key):\r\n",
      "                    raise ValueError('Columns must be same length as key')\r\n",
      "                for k1, k2 in zip(key, value.columns):\r\n",
      "                    self[k1] = value[k2]\r\n",
      "            else:\r\n",
      "                indexer = self.loc._convert_to_indexer(key, axis=1)\r\n",
      "                self._check_setitem_copy()\r\n",
      "                self.loc._setitem_with_indexer((slice(None), indexer), value)\r\n",
      "\r\n",
      "    def _setitem_frame(self, key, value):\r\n",
      "        # support boolean setting with DataFrame input, e.g.\r\n",
      "        # df[df > df2] = 0\r\n",
      "        if key.values.size and not is_bool_dtype(key.values):\r\n",
      "            raise TypeError('Must pass DataFrame with boolean values only')\r\n",
      "\r\n",
      "        self._check_inplace_setting(value)\r\n",
      "        self._check_setitem_copy()\r\n",
      "        self._where(-key, value, inplace=True)\r\n",
      "\r\n",
      "    def _ensure_valid_index(self, value):\r\n",
      "        \"\"\"\r\n",
      "        ensure that if we don't have an index, that we can create one from the\r\n",
      "        passed value\r\n",
      "        \"\"\"\r\n",
      "        # GH5632, make sure that we are a Series convertible\r\n",
      "        if not len(self.index) and is_list_like(value):\r\n",
      "            try:\r\n",
      "                value = Series(value)\r\n",
      "            except:\r\n",
      "                raise ValueError('Cannot set a frame with no defined index '\r\n",
      "                                 'and a value that cannot be converted to a '\r\n",
      "                                 'Series')\r\n",
      "\r\n",
      "            self._data = self._data.reindex_axis(value.index.copy(), axis=1,\r\n",
      "                                                 fill_value=np.nan)\r\n",
      "\r\n",
      "    def _set_item(self, key, value):\r\n",
      "        \"\"\"\r\n",
      "        Add series to DataFrame in specified column.\r\n",
      "\r\n",
      "        If series is a numpy-array (not a Series/TimeSeries), it must be the\r\n",
      "        same length as the DataFrames index or an error will be thrown.\r\n",
      "\r\n",
      "        Series/TimeSeries will be conformed to the DataFrames index to\r\n",
      "        ensure homogeneity.\r\n",
      "        \"\"\"\r\n",
      "\r\n",
      "        self._ensure_valid_index(value)\r\n",
      "        value = self._sanitize_column(key, value)\r\n",
      "        NDFrame._set_item(self, key, value)\r\n",
      "\r\n",
      "        # check if we are modifying a copy\r\n",
      "        # try to set first as we want an invalid\r\n",
      "        # value exception to occur first\r\n",
      "        if len(self):\r\n",
      "            self._check_setitem_copy()\r\n",
      "\r\n",
      "    def insert(self, loc, column, value, allow_duplicates=False):\r\n",
      "        \"\"\"\r\n",
      "        Insert column into DataFrame at specified location.\r\n",
      "\r\n",
      "        Raises a ValueError if `column` is already contained in the DataFrame,\r\n",
      "        unless `allow_duplicates` is set to True.\r\n",
      "\r\n",
      "        Parameters\r\n",
      "        ----------\r\n",
      "        loc : int\r\n",
      "            Insertion index. Must verify 0 <= loc <= len(columns)\r\n",
      "        column : string, number, or hashable object\r\n",
      "            label of the inserted column\r\n",
      "        value : int, Series, or array-like\r\n",
      "        allow_duplicates : bool, optional\r\n",
      "        \"\"\"\r\n",
      "        self._ensure_valid_index(value)\r\n",
      "        value = self._sanitize_column(column, value, broadcast=False)\r\n",
      "        self._data.insert(loc, column, value,\r\n",
      "                          allow_duplicates=allow_duplicates)\r\n",
      "\r\n",
      "    def assign(self, **kwargs):\r\n",
      "        \"\"\"\r\n",
      "        Assign new columns to a DataFrame, returning a new object\r\n",
      "        (a copy) with all the original columns in addition to the new ones.\r\n",
      "\r\n",
      "        Parameters\r\n",
      "        ----------\r\n",
      "        kwargs : keyword, value pairs\r\n",
      "            keywords are the column names. If the values are\r\n",
      "            callable, they are computed on the DataFrame and\r\n",
      "            assigned to the new columns. The callable must not\r\n",
      "            change input DataFrame (though pandas doesn't check it).\r\n",
      "            If the values are not callable, (e.g. a Series, scalar, or array),\r\n",
      "            they are simply assigned.\r\n",
      "\r\n",
      "        Returns\r\n",
      "        -------\r\n",
      "        df : DataFrame\r\n",
      "            A new DataFrame with the new columns in addition to\r\n",
      "            all the existing columns.\r\n",
      "\r\n",
      "        Notes\r\n",
      "        -----\r\n",
      "        For python 3.6 and above, the columns are inserted in the order of\r\n",
      "        \\*\\*kwargs. For python 3.5 and earlier, since \\*\\*kwargs is unordered,\r\n",
      "        the columns are inserted in alphabetical order at the end of your\r\n",
      "        DataFrame.  Assigning multiple columns within the same ``assign``\r\n",
      "        is possible, but you cannot reference other columns created within\r\n",
      "        the same ``assign`` call.\r\n",
      "\r\n",
      "        Examples\r\n",
      "        --------\r\n",
      "        >>> df = DataFrame({'A': range(1, 11), 'B': np.random.randn(10)})\r\n",
      "\r\n",
      "        Where the value is a callable, evaluated on `df`:\r\n",
      "\r\n",
      "        >>> df.assign(ln_A = lambda x: np.log(x.A))\r\n",
      "            A         B      ln_A\r\n",
      "        0   1  0.426905  0.000000\r\n",
      "        1   2 -0.780949  0.693147\r\n",
      "        2   3 -0.418711  1.098612\r\n",
      "        3   4 -0.269708  1.386294\r\n",
      "        4   5 -0.274002  1.609438\r\n",
      "        5   6 -0.500792  1.791759\r\n",
      "        6   7  1.649697  1.945910\r\n",
      "        7   8 -1.495604  2.079442\r\n",
      "        8   9  0.549296  2.197225\r\n",
      "        9  10 -0.758542  2.302585\r\n",
      "\r\n",
      "        Where the value already exists and is inserted:\r\n",
      "\r\n",
      "        >>> newcol = np.log(df['A'])\r\n",
      "        >>> df.assign(ln_A=newcol)\r\n",
      "            A         B      ln_A\r\n",
      "        0   1  0.426905  0.000000\r\n",
      "        1   2 -0.780949  0.693147\r\n",
      "        2   3 -0.418711  1.098612\r\n",
      "        3   4 -0.269708  1.386294\r\n",
      "        4   5 -0.274002  1.609438\r\n",
      "        5   6 -0.500792  1.791759\r\n",
      "        6   7  1.649697  1.945910\r\n",
      "        7   8 -1.495604  2.079442\r\n",
      "        8   9  0.549296  2.197225\r\n",
      "        9  10 -0.758542  2.302585\r\n",
      "        \"\"\"\r\n",
      "        data = self.copy()\r\n",
      "\r\n",
      "        # do all calculations first...\r\n",
      "        results = OrderedDict()\r\n",
      "        for k, v in kwargs.items():\r\n",
      "            results[k] = com._apply_if_callable(v, data)\r\n",
      "\r\n",
      "        # preserve order for 3.6 and later, but sort by key for 3.5 and earlier\r\n",
      "        if PY36:\r\n",
      "            results = results.items()\r\n",
      "        else:\r\n",
      "            results = sorted(results.items())\r\n",
      "        # ... and then assign\r\n",
      "        for k, v in results:\r\n",
      "            data[k] = v\r\n",
      "        return data\r\n",
      "\r\n",
      "    def _sanitize_column(self, key, value, broadcast=True):\r\n",
      "        \"\"\"\r\n",
      "        Ensures new columns (which go into the BlockManager as new blocks) are\r\n",
      "        always copied and converted into an array.\r\n",
      "\r\n",
      "        Parameters\r\n",
      "        ----------\r\n",
      "        key : object\r\n",
      "        value : scalar, Series, or array-like\r\n",
      "        broadcast : bool, default True\r\n",
      "            If ``key`` matches multiple duplicate column names in the\r\n",
      "            DataFrame, this parameter indicates whether ``value`` should be\r\n",
      "            tiled so that the returned array contains a (duplicated) column for\r\n",
      "            each occurrence of the key. If False, ``value`` will not be tiled.\r\n",
      "\r\n",
      "        Returns\r\n",
      "        -------\r\n",
      "        sanitized_column : numpy-array\r\n",
      "        \"\"\"\r\n",
      "\r\n",
      "        def reindexer(value):\r\n",
      "            # reindex if necessary\r\n",
      "\r\n",
      "            if value.index.equals(self.index) or not len(self.index):\r\n",
      "                value = value._values.copy()\r\n",
      "            else:\r\n",
      "\r\n",
      "                # GH 4107\r\n",
      "                try:\r\n",
      "                    value = value.reindex(self.index)._values\r\n",
      "                except Exception as e:\r\n",
      "\r\n",
      "                    # duplicate axis\r\n",
      "                    if not value.index.is_unique:\r\n",
      "                        raise e\r\n",
      "\r\n",
      "                    # other\r\n",
      "                    raise TypeError('incompatible index of inserted column '\r\n",
      "                                    'with frame index')\r\n",
      "            return value\r\n",
      "\r\n",
      "        if isinstance(value, Series):\r\n",
      "            value = reindexer(value)\r\n",
      "\r\n",
      "        elif isinstance(value, DataFrame):\r\n",
      "            # align right-hand-side columns if self.columns\r\n",
      "            # is multi-index and self[key] is a sub-frame\r\n",
      "            if isinstance(self.columns, MultiIndex) and key in self.columns:\r\n",
      "                loc = self.columns.get_loc(key)\r\n",
      "                if isinstance(loc, (slice, Series, np.ndarray, Index)):\r\n",
      "                    cols = maybe_droplevels(self.columns[loc], key)\r\n",
      "                    if len(cols) and not cols.equals(value.columns):\r\n",
      "                        value = value.reindex(cols, axis=1)\r\n",
      "            # now align rows\r\n",
      "            value = reindexer(value).T\r\n",
      "\r\n",
      "        elif isinstance(value, Categorical):\r\n",
      "            value = value.copy()\r\n",
      "\r\n",
      "        elif isinstance(value, Index) or is_sequence(value):\r\n",
      "            from pandas.core.series import _sanitize_index\r\n",
      "\r\n",
      "            # turn me into an ndarray\r\n",
      "            value = _sanitize_index(value, self.index, copy=False)\r\n",
      "            if not isinstance(value, (np.ndarray, Index)):\r\n",
      "                if isinstance(value, list) and len(value) > 0:\r\n",
      "                    value = maybe_convert_platform(value)\r\n",
      "                else:\r\n",
      "                    value = com._asarray_tuplesafe(value)\r\n",
      "            elif value.ndim == 2:\r\n",
      "                value = value.copy().T\r\n",
      "            elif isinstance(value, Index):\r\n",
      "                value = value.copy(deep=True)\r\n",
      "            else:\r\n",
      "                value = value.copy()\r\n",
      "\r\n",
      "            # possibly infer to datetimelike\r\n",
      "            if is_object_dtype(value.dtype):\r\n",
      "                value = maybe_infer_to_datetimelike(value)\r\n",
      "\r\n",
      "        else:\r\n",
      "            # upcast the scalar\r\n",
      "            value = cast_scalar_to_array(len(self.index), value)\r\n",
      "            value = maybe_cast_to_datetime(value, value.dtype)\r\n",
      "\r\n",
      "        # return internal types directly\r\n",
      "        if is_extension_type(value):\r\n",
      "            return value\r\n",
      "\r\n",
      "        # broadcast across multiple columns if necessary\r\n",
      "        if broadcast and key in self.columns and value.ndim == 1:\r\n",
      "            if (not self.columns.is_unique or\r\n",
      "                    isinstance(self.columns, MultiIndex)):\r\n",
      "                existing_piece = self[key]\r\n",
      "                if isinstance(existing_piece, DataFrame):\r\n",
      "                    value = np.tile(value, (len(existing_piece.columns), 1))\r\n",
      "\r\n",
      "        return np.atleast_2d(np.asarray(value))\r\n",
      "\r\n",
      "    @property\r\n",
      "    def _series(self):\r\n",
      "        result = {}\r\n",
      "        for idx, item in enumerate(self.columns):\r\n",
      "            result[item] = Series(self._data.iget(idx), index=self.index,\r\n",
      "                                  name=item)\r\n",
      "        return result\r\n",
      "\r\n",
      "    def lookup(self, row_labels, col_labels):\r\n",
      "        \"\"\"Label-based \"fancy indexing\" function for DataFrame.\r\n",
      "        Given equal-length arrays of row and column labels, return an\r\n",
      "        array of the values corresponding to each (row, col) pair.\r\n",
      "\r\n",
      "        Parameters\r\n",
      "        ----------\r\n",
      "        row_labels : sequence\r\n",
      "            The row labels to use for lookup\r\n",
      "        col_labels : sequence\r\n",
      "            The column labels to use for lookup\r\n",
      "\r\n",
      "        Notes\r\n",
      "        -----\r\n",
      "        Akin to::\r\n",
      "\r\n",
      "            result = []\r\n",
      "            for row, col in zip(row_labels, col_labels):\r\n",
      "                result.append(df.get_value(row, col))\r\n",
      "\r\n",
      "        Examples\r\n",
      "        --------\r\n",
      "        values : ndarray\r\n",
      "            The found values\r\n",
      "\r\n",
      "        \"\"\"\r\n",
      "        n = len(row_labels)\r\n",
      "        if n != len(col_labels):\r\n",
      "            raise ValueError('Row labels must have same size as column labels')\r\n",
      "\r\n",
      "        thresh = 1000\r\n",
      "        if not self._is_mixed_type or n > thresh:\r\n",
      "            values = self.values\r\n",
      "            ridx = self.index.get_indexer(row_labels)\r\n",
      "            cidx = self.columns.get_indexer(col_labels)\r\n",
      "            if (ridx == -1).any():\r\n",
      "                raise KeyError('One or more row labels was not found')\r\n",
      "            if (cidx == -1).any():\r\n",
      "                raise KeyError('One or more column labels was not found')\r\n",
      "            flat_index = ridx * len(self.columns) + cidx\r\n",
      "            result = values.flat[flat_index]\r\n",
      "        else:\r\n",
      "            result = np.empty(n, dtype='O')\r\n",
      "            for i, (r, c) in enumerate(zip(row_labels, col_labels)):\r\n",
      "                result[i] = self._get_value(r, c)\r\n",
      "\r\n",
      "        if is_object_dtype(result):\r\n",
      "            result = lib.maybe_convert_objects(result)\r\n",
      "\r\n",
      "        return result\r\n",
      "\r\n",
      "    # ----------------------------------------------------------------------\r\n",
      "    # Reindexing and alignment\r\n",
      "\r\n",
      "    def _reindex_axes(self, axes, level, limit, tolerance, method, fill_value,\r\n",
      "                      copy):\r\n",
      "        frame = self\r\n",
      "\r\n",
      "        columns = axes['columns']\r\n",
      "        if columns is not None:\r\n",
      "            frame = frame._reindex_columns(columns, method, copy, level,\r\n",
      "                                           fill_value, limit, tolerance)\r\n",
      "\r\n",
      "        index = axes['index']\r\n",
      "        if index is not None:\r\n",
      "            frame = frame._reindex_index(index, method, copy, level,\r\n",
      "                                         fill_value, limit, tolerance)\r\n",
      "\r\n",
      "        return frame\r\n",
      "\r\n",
      "    def _reindex_index(self, new_index, method, copy, level, fill_value=np.nan,\r\n",
      "                       limit=None, tolerance=None):\r\n",
      "        new_index, indexer = self.index.reindex(new_index, method=method,\r\n",
      "                                                level=level, limit=limit,\r\n",
      "                                                tolerance=tolerance)\r\n",
      "        return self._reindex_with_indexers({0: [new_index, indexer]},\r\n",
      "                                           copy=copy, fill_value=fill_value,\r\n",
      "                                           allow_dups=False)\r\n",
      "\r\n",
      "    def _reindex_columns(self, new_columns, method, copy, level,\r\n",
      "                         fill_value=np.nan, limit=None, tolerance=None):\r\n",
      "        new_columns, indexer = self.columns.reindex(new_columns, method=method,\r\n",
      "                                                    level=level, limit=limit,\r\n",
      "                                                    tolerance=tolerance)\r\n",
      "        return self._reindex_with_indexers({1: [new_columns, indexer]},\r\n",
      "                                           copy=copy, fill_value=fill_value,\r\n",
      "                                           allow_dups=False)\r\n",
      "\r\n",
      "    def _reindex_multi(self, axes, copy, fill_value):\r\n",
      "        \"\"\" we are guaranteed non-Nones in the axes! \"\"\"\r\n",
      "\r\n",
      "        new_index, row_indexer = self.index.reindex(axes['index'])\r\n",
      "        new_columns, col_indexer = self.columns.reindex(axes['columns'])\r\n",
      "\r\n",
      "        if row_indexer is not None and col_indexer is not None:\r\n",
      "            indexer = row_indexer, col_indexer\r\n",
      "            new_values = algorithms.take_2d_multi(self.values, indexer,\r\n",
      "                                                  fill_value=fill_value)\r\n",
      "            return self._constructor(new_values, index=new_index,\r\n",
      "                                     columns=new_columns)\r\n",
      "        else:\r\n",
      "            return self._reindex_with_indexers({0: [new_index, row_indexer],\r\n",
      "                                                1: [new_columns, col_indexer]},\r\n",
      "                                               copy=copy,\r\n",
      "                                               fill_value=fill_value)\r\n",
      "\r\n",
      "    @Appender(_shared_docs['align'] % _shared_doc_kwargs)\r\n",
      "    def align(self, other, join='outer', axis=None, level=None, copy=True,\r\n",
      "              fill_value=None, method=None, limit=None, fill_axis=0,\r\n",
      "              broadcast_axis=None):\r\n",
      "        return super(DataFrame, self).align(other, join=join, axis=axis,\r\n",
      "                                            level=level, copy=copy,\r\n",
      "                                            fill_value=fill_value,\r\n",
      "                                            method=method, limit=limit,\r\n",
      "                                            fill_axis=fill_axis,\r\n",
      "                                            broadcast_axis=broadcast_axis)\r\n",
      "\r\n",
      "    @Appender(_shared_docs['reindex'] % _shared_doc_kwargs)\r\n",
      "    @rewrite_axis_style_signature('labels', [('method', None),\r\n",
      "                                             ('copy', True),\r\n",
      "                                             ('level', None),\r\n",
      "                                             ('fill_value', np.nan),\r\n",
      "                                             ('limit', None),\r\n",
      "                                             ('tolerance', None)])\r\n",
      "    def reindex(self, *args, **kwargs):\r\n",
      "        axes = validate_axis_style_args(self, args, kwargs, 'labels',\r\n",
      "                                        'reindex')\r\n",
      "        kwargs.update(axes)\r\n",
      "        # Pop these, since the values are in `kwargs` under different names\r\n",
      "        kwargs.pop('axis', None)\r\n",
      "        kwargs.pop('labels', None)\r\n",
      "        return super(DataFrame, self).reindex(**kwargs)\r\n",
      "\r\n",
      "    @Appender(_shared_docs['reindex_axis'] % _shared_doc_kwargs)\r\n",
      "    def reindex_axis(self, labels, axis=0, method=None, level=None, copy=True,\r\n",
      "                     limit=None, fill_value=np.nan):\r\n",
      "        return super(DataFrame,\r\n",
      "                     self).reindex_axis(labels=labels, axis=axis,\r\n",
      "                                        method=method, level=level, copy=copy,\r\n",
      "                                        limit=limit, fill_value=fill_value)\r\n",
      "\r\n",
      "    @rewrite_axis_style_signature('mapper', [('copy', True),\r\n",
      "                                             ('inplace', False),\r\n",
      "                                             ('level', None)])\r\n",
      "    def rename(self, *args, **kwargs):\r\n",
      "        \"\"\"Alter axes labels.\r\n",
      "\r\n",
      "        Function / dict values must be unique (1-to-1). Labels not contained in\r\n",
      "        a dict / Series will be left as-is. Extra labels listed don't throw an\r\n",
      "        error.\r\n",
      "\r\n",
      "        See the :ref:`user guide <basics.rename>` for more.\r\n",
      "\r\n",
      "        Parameters\r\n",
      "        ----------\r\n",
      "        mapper, index, columns : dict-like or function, optional\r\n",
      "            dict-like or functions transformations to apply to\r\n",
      "            that axis' values. Use either ``mapper`` and ``axis`` to\r\n",
      "            specify the axis to target with ``mapper``, or ``index`` and\r\n",
      "            ``columns``.\r\n",
      "        axis : int or str, optional\r\n",
      "            Axis to target with ``mapper``. Can be either the axis name\r\n",
      "            ('index', 'columns') or number (0, 1). The default is 'index'.\r\n",
      "        copy : boolean, default True\r\n",
      "            Also copy underlying data\r\n",
      "        inplace : boolean, default False\r\n",
      "            Whether to return a new %(klass)s. If True then value of copy is\r\n",
      "            ignored.\r\n",
      "        level : int or level name, default None\r\n",
      "            In case of a MultiIndex, only rename labels in the specified\r\n",
      "            level.\r\n",
      "\r\n",
      "        Returns\r\n",
      "        -------\r\n",
      "        renamed : DataFrame\r\n",
      "\r\n",
      "        See Also\r\n",
      "        --------\r\n",
      "        pandas.DataFrame.rename_axis\r\n",
      "\r\n",
      "        Examples\r\n",
      "        --------\r\n",
      "\r\n",
      "        ``DataFrame.rename`` supports two calling conventions\r\n",
      "\r\n",
      "        * ``(index=index_mapper, columns=columns_mapper, ...)``\r\n",
      "        * ``(mapper, axis={'index', 'columns'}, ...)``\r\n",
      "\r\n",
      "        We *highly* recommend using keyword arguments to clarify your\r\n",
      "        intent.\r\n",
      "\r\n",
      "        >>> df = pd.DataFrame({\"A\": [1, 2, 3], \"B\": [4, 5, 6]})\r\n",
      "        >>> df.rename(index=str, columns={\"A\": \"a\", \"B\": \"c\"})\r\n",
      "           a  c\r\n",
      "        0  1  4\r\n",
      "        1  2  5\r\n",
      "        2  3  6\r\n",
      "\r\n",
      "        >>> df.rename(index=str, columns={\"A\": \"a\", \"C\": \"c\"})\r\n",
      "           a  B\r\n",
      "        0  1  4\r\n",
      "        1  2  5\r\n",
      "        2  3  6\r\n",
      "\r\n",
      "        Using axis-style parameters\r\n",
      "\r\n",
      "        >>> df.rename(str.lower, axis='columns')\r\n",
      "           a  b\r\n",
      "        0  1  4\r\n",
      "        1  2  5\r\n",
      "        2  3  6\r\n",
      "\r\n",
      "        >>> df.rename({1: 2, 2: 4}, axis='index')\r\n",
      "           A  B\r\n",
      "        0  1  4\r\n",
      "        2  2  5\r\n",
      "        4  3  6\r\n",
      "        \"\"\"\r\n",
      "        axes = validate_axis_style_args(self, args, kwargs, 'mapper', 'rename')\r\n",
      "        kwargs.update(axes)\r\n",
      "        # Pop these, since the values are in `kwargs` under different names\r\n",
      "        kwargs.pop('axis', None)\r\n",
      "        kwargs.pop('mapper', None)\r\n",
      "        return super(DataFrame, self).rename(**kwargs)\r\n",
      "\r\n",
      "    @Appender(_shared_docs['fillna'] % _shared_doc_kwargs)\r\n",
      "    def fillna(self, value=None, method=None, axis=None, inplace=False,\r\n",
      "               limit=None, downcast=None, **kwargs):\r\n",
      "        return super(DataFrame,\r\n",
      "                     self).fillna(value=value, method=method, axis=axis,\r\n",
      "                                  inplace=inplace, limit=limit,\r\n",
      "                                  downcast=downcast, **kwargs)\r\n",
      "\r\n",
      "    @Appender(_shared_docs['shift'] % _shared_doc_kwargs)\r\n",
      "    def shift(self, periods=1, freq=None, axis=0):\r\n",
      "        return super(DataFrame, self).shift(periods=periods, freq=freq,\r\n",
      "                                            axis=axis)\r\n",
      "\r\n",
      "    def set_index(self, keys, drop=True, append=False, inplace=False,\r\n",
      "                  verify_integrity=False):\r\n",
      "        \"\"\"\r\n",
      "        Set the DataFrame index (row labels) using one or more existing\r\n",
      "        columns. By default yields a new object.\r\n",
      "\r\n",
      "        Parameters\r\n",
      "        ----------\r\n",
      "        keys : column label or list of column labels / arrays\r\n",
      "        drop : boolean, default True\r\n",
      "            Delete columns to be used as the new index\r\n",
      "        append : boolean, default False\r\n",
      "            Whether to append columns to existing index\r\n",
      "        inplace : boolean, default False\r\n",
      "            Modify the DataFrame in place (do not create a new object)\r\n",
      "        verify_integrity : boolean, default False\r\n",
      "            Check the new index for duplicates. Otherwise defer the check until\r\n",
      "            necessary. Setting to False will improve the performance of this\r\n",
      "            method\r\n",
      "\r\n",
      "        Examples\r\n",
      "        --------\r\n",
      "        >>> df = pd.DataFrame({'month': [1, 4, 7, 10],\r\n",
      "        ...                    'year': [2012, 2014, 2013, 2014],\r\n",
      "        ...                    'sale':[55, 40, 84, 31]})\r\n",
      "           month  sale  year\r\n",
      "        0  1      55    2012\r\n",
      "        1  4      40    2014\r\n",
      "        2  7      84    2013\r\n",
      "        3  10     31    2014\r\n",
      "\r\n",
      "        Set the index to become the 'month' column:\r\n",
      "\r\n",
      "        >>> df.set_index('month')\r\n",
      "               sale  year\r\n",
      "        month\r\n",
      "        1      55    2012\r\n",
      "        4      40    2014\r\n",
      "        7      84    2013\r\n",
      "        10     31    2014\r\n",
      "\r\n",
      "        Create a multi-index using columns 'year' and 'month':\r\n",
      "\r\n",
      "        >>> df.set_index(['year', 'month'])\r\n",
      "                    sale\r\n",
      "        year  month\r\n",
      "        2012  1     55\r\n",
      "        2014  4     40\r\n",
      "        2013  7     84\r\n",
      "        2014  10    31\r\n",
      "\r\n",
      "        Create a multi-index using a set of values and a column:\r\n",
      "\r\n",
      "        >>> df.set_index([[1, 2, 3, 4], 'year'])\r\n",
      "                 month  sale\r\n",
      "           year\r\n",
      "        1  2012  1      55\r\n",
      "        2  2014  4      40\r\n",
      "        3  2013  7      84\r\n",
      "        4  2014  10     31\r\n",
      "\r\n",
      "        Returns\r\n",
      "        -------\r\n",
      "        dataframe : DataFrame\r\n",
      "        \"\"\"\r\n",
      "        inplace = validate_bool_kwarg(inplace, 'inplace')\r\n",
      "        if not isinstance(keys, list):\r\n",
      "            keys = [keys]\r\n",
      "\r\n",
      "        if inplace:\r\n",
      "            frame = self\r\n",
      "        else:\r\n",
      "            frame = self.copy()\r\n",
      "\r\n",
      "        arrays = []\r\n",
      "        names = []\r\n",
      "        if append:\r\n",
      "            names = [x for x in self.index.names]\r\n",
      "            if isinstance(self.index, MultiIndex):\r\n",
      "                for i in range(self.index.nlevels):\r\n",
      "                    arrays.append(self.index._get_level_values(i))\r\n",
      "            else:\r\n",
      "                arrays.append(self.index)\r\n",
      "\r\n",
      "        to_remove = []\r\n",
      "        for col in keys:\r\n",
      "            if isinstance(col, MultiIndex):\r\n",
      "                # append all but the last column so we don't have to modify\r\n",
      "                # the end of this loop\r\n",
      "                for n in range(col.nlevels - 1):\r\n",
      "                    arrays.append(col._get_level_values(n))\r\n",
      "\r\n",
      "                level = col._get_level_values(col.nlevels - 1)\r\n",
      "                names.extend(col.names)\r\n",
      "            elif isinstance(col, Series):\r\n",
      "                level = col._values\r\n",
      "                names.append(col.name)\r\n",
      "            elif isinstance(col, Index):\r\n",
      "                level = col\r\n",
      "                names.append(col.name)\r\n",
      "            elif isinstance(col, (list, np.ndarray, Index)):\r\n",
      "                level = col\r\n",
      "                names.append(None)\r\n",
      "            else:\r\n",
      "                level = frame[col]._values\r\n",
      "                names.append(col)\r\n",
      "                if drop:\r\n",
      "                    to_remove.append(col)\r\n",
      "            arrays.append(level)\r\n",
      "\r\n",
      "        index = _ensure_index_from_sequences(arrays, names)\r\n",
      "\r\n",
      "        if verify_integrity and not index.is_unique:\r\n",
      "            duplicates = index.get_duplicates()\r\n",
      "            raise ValueError('Index has duplicate keys: %s' % duplicates)\r\n",
      "\r\n",
      "        for c in to_remove:\r\n",
      "            del frame[c]\r\n",
      "\r\n",
      "        # clear up memory usage\r\n",
      "        index._cleanup()\r\n",
      "\r\n",
      "        frame.index = index\r\n",
      "\r\n",
      "        if not inplace:\r\n",
      "            return frame\r\n",
      "\r\n",
      "    def reset_index(self, level=None, drop=False, inplace=False, col_level=0,\r\n",
      "                    col_fill=''):\r\n",
      "        \"\"\"\r\n",
      "        For DataFrame with multi-level index, return new DataFrame with\r\n",
      "        labeling information in the columns under the index names, defaulting\r\n",
      "        to 'level_0', 'level_1', etc. if any are None. For a standard index,\r\n",
      "        the index name will be used (if set), otherwise a default 'index' or\r\n",
      "        'level_0' (if 'index' is already taken) will be used.\r\n",
      "\r\n",
      "        Parameters\r\n",
      "        ----------\r\n",
      "        level : int, str, tuple, or list, default None\r\n",
      "            Only remove the given levels from the index. Removes all levels by\r\n",
      "            default\r\n",
      "        drop : boolean, default False\r\n",
      "            Do not try to insert index into dataframe columns. This resets\r\n",
      "            the index to the default integer index.\r\n",
      "        inplace : boolean, default False\r\n",
      "            Modify the DataFrame in place (do not create a new object)\r\n",
      "        col_level : int or str, default 0\r\n",
      "            If the columns have multiple levels, determines which level the\r\n",
      "            labels are inserted into. By default it is inserted into the first\r\n",
      "            level.\r\n",
      "        col_fill : object, default ''\r\n",
      "            If the columns have multiple levels, determines how the other\r\n",
      "            levels are named. If None then the index name is repeated.\r\n",
      "\r\n",
      "        Returns\r\n",
      "        -------\r\n",
      "        resetted : DataFrame\r\n",
      "\r\n",
      "        Examples\r\n",
      "        --------\r\n",
      "        >>> df = pd.DataFrame([('bird',    389.0),\r\n",
      "        ...                    ('bird',     24.0),\r\n",
      "        ...                    ('mammal',   80.5),\r\n",
      "        ...                    ('mammal', np.nan)],\r\n",
      "        ...                   index=['falcon', 'parrot', 'lion', 'monkey'],\r\n",
      "        ...                   columns=('class', 'max_speed'))\r\n",
      "        >>> df\r\n",
      "                 class  max_speed\r\n",
      "        falcon    bird      389.0\r\n",
      "        parrot    bird       24.0\r\n",
      "        lion    mammal       80.5\r\n",
      "        monkey  mammal        NaN\r\n",
      "\r\n",
      "        When we reset the index, the old index is added as a column, and a\r\n",
      "        new sequential index is used:\r\n",
      "\r\n",
      "        >>> df.reset_index()\r\n",
      "            index   class  max_speed\r\n",
      "        0  falcon    bird      389.0\r\n",
      "        1  parrot    bird       24.0\r\n",
      "        2    lion  mammal       80.5\r\n",
      "        3  monkey  mammal        NaN\r\n",
      "\r\n",
      "        We can use the `drop` parameter to avoid the old index being added as\r\n",
      "        a column:\r\n",
      "\r\n",
      "        >>> df.reset_index(drop=True)\r\n",
      "            class  max_speed\r\n",
      "        0    bird      389.0\r\n",
      "        1    bird       24.0\r\n",
      "        2  mammal       80.5\r\n",
      "        3  mammal        NaN\r\n",
      "\r\n",
      "        You can also use `reset_index` with `MultiIndex`.\r\n",
      "\r\n",
      "        >>> index = pd.MultiIndex.from_tuples([('bird', 'falcon'),\r\n",
      "        ...                                    ('bird', 'parrot'),\r\n",
      "        ...                                    ('mammal', 'lion'),\r\n",
      "        ...                                    ('mammal', 'monkey')],\r\n",
      "        ...                                   names=['class', 'name'])\r\n",
      "        >>> columns = pd.MultiIndex.from_tuples([('speed', 'max'),\r\n",
      "        ...                                      ('species', 'type')])\r\n",
      "        >>> df = pd.DataFrame([(389.0, 'fly'),\r\n",
      "        ...                    ( 24.0, 'fly'),\r\n",
      "        ...                    ( 80.5, 'run'),\r\n",
      "        ...                    (np.nan, 'jump')],\r\n",
      "        ...                   index=index,\r\n",
      "        ...                   columns=columns)\r\n",
      "        >>> df\r\n",
      "                       speed species\r\n",
      "                         max    type\r\n",
      "        class  name\r\n",
      "        bird   falcon  389.0     fly\r\n",
      "               parrot   24.0     fly\r\n",
      "        mammal lion     80.5     run\r\n",
      "               monkey    NaN    jump\r\n",
      "\r\n",
      "        If the index has multiple levels, we can reset a subset of them:\r\n",
      "\r\n",
      "        >>> df.reset_index(level='class')\r\n",
      "                 class  speed species\r\n",
      "                          max    type\r\n",
      "        name\r\n",
      "        falcon    bird  389.0     fly\r\n",
      "        parrot    bird   24.0     fly\r\n",
      "        lion    mammal   80.5     run\r\n",
      "        monkey  mammal    NaN    jump\r\n",
      "\r\n",
      "        If we are not dropping the index, by default, it is placed in the top\r\n",
      "        level. We can place it in another level:\r\n",
      "\r\n",
      "        >>> df.reset_index(level='class', col_level=1)\r\n",
      "                        speed species\r\n",
      "                 class    max    type\r\n",
      "        name\r\n",
      "        falcon    bird  389.0     fly\r\n",
      "        parrot    bird   24.0     fly\r\n",
      "        lion    mammal   80.5     run\r\n",
      "        monkey  mammal    NaN    jump\r\n",
      "\r\n",
      "        When the index is inserted under another level, we can specify under\r\n",
      "        which one with the parameter `col_fill`:\r\n",
      "\r\n",
      "        >>> df.reset_index(level='class', col_level=1, col_fill='species')\r\n",
      "                      species  speed species\r\n",
      "                        class    max    type\r\n",
      "        name\r\n",
      "        falcon           bird  389.0     fly\r\n",
      "        parrot           bird   24.0     fly\r\n",
      "        lion           mammal   80.5     run\r\n",
      "        monkey         mammal    NaN    jump\r\n",
      "\r\n",
      "        If we specify a nonexistent level for `col_fill`, it is created:\r\n",
      "\r\n",
      "        >>> df.reset_index(level='class', col_level=1, col_fill='genus')\r\n",
      "                        genus  speed species\r\n",
      "                        class    max    type\r\n",
      "        name\r\n",
      "        falcon           bird  389.0     fly\r\n",
      "        parrot           bird   24.0     fly\r\n",
      "        lion           mammal   80.5     run\r\n",
      "        monkey         mammal    NaN    jump\r\n",
      "        \"\"\"\r\n",
      "        inplace = validate_bool_kwarg(inplace, 'inplace')\r\n",
      "        if inplace:\r\n",
      "            new_obj = self\r\n",
      "        else:\r\n",
      "            new_obj = self.copy()\r\n",
      "\r\n",
      "        def _maybe_casted_values(index, labels=None):\r\n",
      "            if isinstance(index, PeriodIndex):\r\n",
      "                values = index.asobject.values\r\n",
      "            elif isinstance(index, DatetimeIndex) and index.tz is not None:\r\n",
      "                values = index\r\n",
      "            else:\r\n",
      "                values = index.values\r\n",
      "                if values.dtype == np.object_:\r\n",
      "                    values = lib.maybe_convert_objects(values)\r\n",
      "\r\n",
      "            # if we have the labels, extract the values with a mask\r\n",
      "            if labels is not None:\r\n",
      "                mask = labels == -1\r\n",
      "\r\n",
      "                # we can have situations where the whole mask is -1,\r\n",
      "                # meaning there is nothing found in labels, so make all nan's\r\n",
      "                if mask.all():\r\n",
      "                    values = np.empty(len(mask))\r\n",
      "                    values.fill(np.nan)\r\n",
      "                else:\r\n",
      "                    values = values.take(labels)\r\n",
      "                    if mask.any():\r\n",
      "                        values, changed = maybe_upcast_putmask(\r\n",
      "                            values, mask, np.nan)\r\n",
      "            return values\r\n",
      "\r\n",
      "        new_index = _default_index(len(new_obj))\r\n",
      "        if level is not None:\r\n",
      "            if not isinstance(level, (tuple, list)):\r\n",
      "                level = [level]\r\n",
      "            level = [self.index._get_level_number(lev) for lev in level]\r\n",
      "            if isinstance(self.index, MultiIndex):\r\n",
      "                if len(level) < self.index.nlevels:\r\n",
      "                    new_index = self.index.droplevel(level)\r\n",
      "\r\n",
      "        if not drop:\r\n",
      "            if isinstance(self.index, MultiIndex):\r\n",
      "                names = [n if n is not None else ('level_%d' % i)\r\n",
      "                         for (i, n) in enumerate(self.index.names)]\r\n",
      "                to_insert = lzip(self.index.levels, self.index.labels)\r\n",
      "            else:\r\n",
      "                default = 'index' if 'index' not in self else 'level_0'\r\n",
      "                names = ([default] if self.index.name is None\r\n",
      "                         else [self.index.name])\r\n",
      "                to_insert = ((self.index, None),)\r\n",
      "\r\n",
      "            multi_col = isinstance(self.columns, MultiIndex)\r\n",
      "            for i, (lev, lab) in reversed(list(enumerate(to_insert))):\r\n",
      "                if not (level is None or i in level):\r\n",
      "                    continue\r\n",
      "                name = names[i]\r\n",
      "                if multi_col:\r\n",
      "                    col_name = (list(name) if isinstance(name, tuple)\r\n",
      "                                else [name])\r\n",
      "                    if col_fill is None:\r\n",
      "                        if len(col_name) not in (1, self.columns.nlevels):\r\n",
      "                            raise ValueError(\"col_fill=None is incompatible \"\r\n",
      "                                             \"with incomplete column name \"\r\n",
      "                                             \"{}\".format(name))\r\n",
      "                        col_fill = col_name[0]\r\n",
      "\r\n",
      "                    lev_num = self.columns._get_level_number(col_level)\r\n",
      "                    name_lst = [col_fill] * lev_num + col_name\r\n",
      "                    missing = self.columns.nlevels - len(name_lst)\r\n",
      "                    name_lst += [col_fill] * missing\r\n",
      "                    name = tuple(name_lst)\r\n",
      "                # to ndarray and maybe infer different dtype\r\n",
      "                level_values = _maybe_casted_values(lev, lab)\r\n",
      "                new_obj.insert(0, name, level_values)\r\n",
      "\r\n",
      "        new_obj.index = new_index\r\n",
      "        if not inplace:\r\n",
      "            return new_obj\r\n",
      "\r\n",
      "    # ----------------------------------------------------------------------\r\n",
      "    # Reindex-based selection methods\r\n",
      "\r\n",
      "    @Appender(_shared_docs['isna'] % _shared_doc_kwargs)\r\n",
      "    def isna(self):\r\n",
      "        return super(DataFrame, self).isna()\r\n",
      "\r\n",
      "    @Appender(_shared_docs['isna'] % _shared_doc_kwargs)\r\n",
      "    def isnull(self):\r\n",
      "        return super(DataFrame, self).isnull()\r\n",
      "\r\n",
      "    @Appender(_shared_docs['notna'] % _shared_doc_kwargs)\r\n",
      "    def notna(self):\r\n",
      "        return super(DataFrame, self).notna()\r\n",
      "\r\n",
      "    @Appender(_shared_docs['notna'] % _shared_doc_kwargs)\r\n",
      "    def notnull(self):\r\n",
      "        return super(DataFrame, self).notnull()\r\n",
      "\r\n",
      "    def dropna(self, axis=0, how='any', thresh=None, subset=None,\r\n",
      "               inplace=False):\r\n",
      "        \"\"\"\r\n",
      "        Return object with labels on given axis omitted where alternately any\r\n",
      "        or all of the data are missing\r\n",
      "\r\n",
      "        Parameters\r\n",
      "        ----------\r\n",
      "        axis : {0 or 'index', 1 or 'columns'}, or tuple/list thereof\r\n",
      "            Pass tuple or list to drop on multiple axes\r\n",
      "        how : {'any', 'all'}\r\n",
      "            * any : if any NA values are present, drop that label\r\n",
      "            * all : if all values are NA, drop that label\r\n",
      "        thresh : int, default None\r\n",
      "            int value : require that many non-NA values\r\n",
      "        subset : array-like\r\n",
      "            Labels along other axis to consider, e.g. if you are dropping rows\r\n",
      "            these would be a list of columns to include\r\n",
      "        inplace : boolean, default False\r\n",
      "            If True, do operation inplace and return None.\r\n",
      "\r\n",
      "        Returns\r\n",
      "        -------\r\n",
      "        dropped : DataFrame\r\n",
      "\r\n",
      "        Examples\r\n",
      "        --------\r\n",
      "        >>> df = pd.DataFrame([[np.nan, 2, np.nan, 0], [3, 4, np.nan, 1],\r\n",
      "        ...                    [np.nan, np.nan, np.nan, 5]],\r\n",
      "        ...                   columns=list('ABCD'))\r\n",
      "        >>> df\r\n",
      "             A    B   C  D\r\n",
      "        0  NaN  2.0 NaN  0\r\n",
      "        1  3.0  4.0 NaN  1\r\n",
      "        2  NaN  NaN NaN  5\r\n",
      "\r\n",
      "        Drop the columns where all elements are nan:\r\n",
      "\r\n",
      "        >>> df.dropna(axis=1, how='all')\r\n",
      "             A    B  D\r\n",
      "        0  NaN  2.0  0\r\n",
      "        1  3.0  4.0  1\r\n",
      "        2  NaN  NaN  5\r\n",
      "\r\n",
      "        Drop the columns where any of the elements is nan\r\n",
      "\r\n",
      "        >>> df.dropna(axis=1, how='any')\r\n",
      "           D\r\n",
      "        0  0\r\n",
      "        1  1\r\n",
      "        2  5\r\n",
      "\r\n",
      "        Drop the rows where all of the elements are nan\r\n",
      "        (there is no row to drop, so df stays the same):\r\n",
      "\r\n",
      "        >>> df.dropna(axis=0, how='all')\r\n",
      "             A    B   C  D\r\n",
      "        0  NaN  2.0 NaN  0\r\n",
      "        1  3.0  4.0 NaN  1\r\n",
      "        2  NaN  NaN NaN  5\r\n",
      "\r\n",
      "        Keep only the rows with at least 2 non-na values:\r\n",
      "\r\n",
      "        >>> df.dropna(thresh=2)\r\n",
      "             A    B   C  D\r\n",
      "        0  NaN  2.0 NaN  0\r\n",
      "        1  3.0  4.0 NaN  1\r\n",
      "\r\n",
      "        \"\"\"\r\n",
      "        inplace = validate_bool_kwarg(inplace, 'inplace')\r\n",
      "        if isinstance(axis, (tuple, list)):\r\n",
      "            result = self\r\n",
      "            for ax in axis:\r\n",
      "                result = result.dropna(how=how, thresh=thresh, subset=subset,\r\n",
      "                                       axis=ax)\r\n",
      "        else:\r\n",
      "            axis = self._get_axis_number(axis)\r\n",
      "            agg_axis = 1 - axis\r\n",
      "\r\n",
      "            agg_obj = self\r\n",
      "            if subset is not None:\r\n",
      "                ax = self._get_axis(agg_axis)\r\n",
      "                indices = ax.get_indexer_for(subset)\r\n",
      "                check = indices == -1\r\n",
      "                if check.any():\r\n",
      "                    raise KeyError(list(np.compress(check, subset)))\r\n",
      "                agg_obj = self.take(indices, axis=agg_axis)\r\n",
      "\r\n",
      "            count = agg_obj.count(axis=agg_axis)\r\n",
      "\r\n",
      "            if thresh is not None:\r\n",
      "                mask = count >= thresh\r\n",
      "            elif how == 'any':\r\n",
      "                mask = count == len(agg_obj._get_axis(agg_axis))\r\n",
      "            elif how == 'all':\r\n",
      "                mask = count > 0\r\n",
      "            else:\r\n",
      "                if how is not None:\r\n",
      "                    raise ValueError('invalid how option: %s' % how)\r\n",
      "                else:\r\n",
      "                    raise TypeError('must specify how or thresh')\r\n",
      "\r\n",
      "            result = self._take(mask.nonzero()[0], axis=axis, convert=False)\r\n",
      "\r\n",
      "        if inplace:\r\n",
      "            self._update_inplace(result)\r\n",
      "        else:\r",
      "\r\n",
      "            return result\r\n",
      "\r\n",
      "    def drop_duplicates(self, subset=None, keep='first', inplace=False):\r\n",
      "        \"\"\"\r\n",
      "        Return DataFrame with duplicate rows removed, optionally only\r\n",
      "        considering certain columns\r\n",
      "\r\n",
      "        Parameters\r\n",
      "        ----------\r\n",
      "        subset : column label or sequence of labels, optional\r\n",
      "            Only consider certain columns for identifying duplicates, by\r\n",
      "            default use all of the columns\r\n",
      "        keep : {'first', 'last', False}, default 'first'\r\n",
      "            - ``first`` : Drop duplicates except for the first occurrence.\r\n",
      "            - ``last`` : Drop duplicates except for the last occurrence.\r\n",
      "            - False : Drop all duplicates.\r\n",
      "        inplace : boolean, default False\r\n",
      "            Whether to drop duplicates in place or to return a copy\r\n",
      "\r\n",
      "        Returns\r\n",
      "        -------\r\n",
      "        deduplicated : DataFrame\r\n",
      "        \"\"\"\r\n",
      "        inplace = validate_bool_kwarg(inplace, 'inplace')\r\n",
      "        duplicated = self.duplicated(subset, keep=keep)\r\n",
      "\r\n",
      "        if inplace:\r\n",
      "            inds, = (-duplicated).nonzero()\r\n",
      "            new_data = self._data.take(inds)\r\n",
      "            self._update_inplace(new_data)\r\n",
      "        else:\r\n",
      "            return self[-duplicated]\r\n",
      "\r\n",
      "    def duplicated(self, subset=None, keep='first'):\r\n",
      "        \"\"\"\r\n",
      "        Return boolean Series denoting duplicate rows, optionally only\r\n",
      "        considering certain columns\r\n",
      "\r\n",
      "        Parameters\r\n",
      "        ----------\r\n",
      "        subset : column label or sequence of labels, optional\r\n",
      "            Only consider certain columns for identifying duplicates, by\r\n",
      "            default use all of the columns\r\n",
      "        keep : {'first', 'last', False}, default 'first'\r\n",
      "            - ``first`` : Mark duplicates as ``True`` except for the\r\n",
      "              first occurrence.\r\n",
      "            - ``last`` : Mark duplicates as ``True`` except for the\r\n",
      "              last occurrence.\r\n",
      "            - False : Mark all duplicates as ``True``.\r\n",
      "\r\n",
      "        Returns\r\n",
      "        -------\r\n",
      "        duplicated : Series\r\n",
      "        \"\"\"\r\n",
      "        from pandas.core.sorting import get_group_index\r\n",
      "        from pandas._libs.hashtable import duplicated_int64, _SIZE_HINT_LIMIT\r\n",
      "\r\n",
      "        def f(vals):\r\n",
      "            labels, shape = algorithms.factorize(\r\n",
      "                vals, size_hint=min(len(self), _SIZE_HINT_LIMIT))\r\n",
      "            return labels.astype('i8', copy=False), len(shape)\r\n",
      "\r\n",
      "        if subset is None:\r\n",
      "            subset = self.columns\r\n",
      "        elif (not np.iterable(subset) or\r\n",
      "              isinstance(subset, compat.string_types) or\r\n",
      "              isinstance(subset, tuple) and subset in self.columns):\r\n",
      "            subset = subset,\r\n",
      "\r\n",
      "        vals = (col.values for name, col in self.iteritems()\r\n",
      "                if name in subset)\r\n",
      "        labels, shape = map(list, zip(*map(f, vals)))\r\n",
      "\r\n",
      "        ids = get_group_index(labels, shape, sort=False, xnull=False)\r\n",
      "        return Series(duplicated_int64(ids, keep), index=self.index)\r\n",
      "\r\n",
      "    # ----------------------------------------------------------------------\r\n",
      "    # Sorting\r\n",
      "\r\n",
      "    @Appender(_shared_docs['sort_values'] % _shared_doc_kwargs)\r\n",
      "    def sort_values(self, by, axis=0, ascending=True, inplace=False,\r\n",
      "                    kind='quicksort', na_position='last'):\r\n",
      "        inplace = validate_bool_kwarg(inplace, 'inplace')\r\n",
      "        axis = self._get_axis_number(axis)\r\n",
      "        other_axis = 0 if axis == 1 else 1\r\n",
      "\r\n",
      "        if not isinstance(by, list):\r\n",
      "            by = [by]\r\n",
      "        if is_sequence(ascending) and len(by) != len(ascending):\r\n",
      "            raise ValueError('Length of ascending (%d) != length of by (%d)' %\r\n",
      "                             (len(ascending), len(by)))\r\n",
      "        if len(by) > 1:\r\n",
      "            from pandas.core.sorting import lexsort_indexer\r\n",
      "\r\n",
      "            keys = []\r\n",
      "            for x in by:\r\n",
      "                k = self.xs(x, axis=other_axis).values\r\n",
      "                if k.ndim == 2:\r\n",
      "                    raise ValueError('Cannot sort by duplicate column %s' %\r\n",
      "                                     str(x))\r\n",
      "                keys.append(k)\r\n",
      "            indexer = lexsort_indexer(keys, orders=ascending,\r\n",
      "                                      na_position=na_position)\r\n",
      "            indexer = _ensure_platform_int(indexer)\r\n",
      "        else:\r\n",
      "            from pandas.core.sorting import nargsort\r\n",
      "\r\n",
      "            by = by[0]\r\n",
      "            k = self.xs(by, axis=other_axis).values\r\n",
      "            if k.ndim == 2:\r\n",
      "\r\n",
      "                # try to be helpful\r\n",
      "                if isinstance(self.columns, MultiIndex):\r\n",
      "                    raise ValueError('Cannot sort by column %s in a '\r\n",
      "                                     'multi-index you need to explicitly '\r\n",
      "                                     'provide all the levels' % str(by))\r\n",
      "\r\n",
      "                raise ValueError('Cannot sort by duplicate column %s' %\r\n",
      "                                 str(by))\r\n",
      "            if isinstance(ascending, (tuple, list)):\r\n",
      "                ascending = ascending[0]\r\n",
      "\r\n",
      "            indexer = nargsort(k, kind=kind, ascending=ascending,\r\n",
      "                               na_position=na_position)\r\n",
      "\r\n",
      "        new_data = self._data.take(indexer,\r\n",
      "                                   axis=self._get_block_manager_axis(axis),\r\n",
      "                                   verify=False)\r\n",
      "\r\n",
      "        if inplace:\r\n",
      "            return self._update_inplace(new_data)\r\n",
      "        else:\r\n",
      "            return self._constructor(new_data).__finalize__(self)\r\n",
      "\r\n",
      "    @Appender(_shared_docs['sort_index'] % _shared_doc_kwargs)\r\n",
      "    def sort_index(self, axis=0, level=None, ascending=True, inplace=False,\r\n",
      "                   kind='quicksort', na_position='last', sort_remaining=True,\r\n",
      "                   by=None):\r\n",
      "\r\n",
      "        # TODO: this can be combined with Series.sort_index impl as\r\n",
      "        # almost identical\r\n",
      "\r\n",
      "        inplace = validate_bool_kwarg(inplace, 'inplace')\r\n",
      "        # 10726\r\n",
      "        if by is not None:\r\n",
      "            warnings.warn(\"by argument to sort_index is deprecated, \"\r\n",
      "                          \"please use .sort_values(by=...)\",\r\n",
      "                          FutureWarning, stacklevel=2)\r\n",
      "            if level is not None:\r\n",
      "                raise ValueError(\"unable to simultaneously sort by and level\")\r\n",
      "            return self.sort_values(by, axis=axis, ascending=ascending,\r\n",
      "                                    inplace=inplace)\r\n",
      "\r\n",
      "        axis = self._get_axis_number(axis)\r\n",
      "        labels = self._get_axis(axis)\r\n",
      "\r\n",
      "        if level:\r\n",
      "\r\n",
      "            new_axis, indexer = labels.sortlevel(level, ascending=ascending,\r\n",
      "                                                 sort_remaining=sort_remaining)\r\n",
      "\r\n",
      "        elif isinstance(labels, MultiIndex):\r\n",
      "            from pandas.core.sorting import lexsort_indexer\r\n",
      "\r\n",
      "            # make sure that the axis is lexsorted to start\r\n",
      "            # if not we need to reconstruct to get the correct indexer\r\n",
      "            labels = labels._sort_levels_monotonic()\r\n",
      "            indexer = lexsort_indexer(labels._get_labels_for_sorting(),\r\n",
      "                                      orders=ascending,\r\n",
      "                                      na_position=na_position)\r\n",
      "        else:\r\n",
      "            from pandas.core.sorting import nargsort\r\n",
      "\r\n",
      "            # Check monotonic-ness before sort an index\r\n",
      "            # GH11080\r\n",
      "            if ((ascending and labels.is_monotonic_increasing) or\r\n",
      "                    (not ascending and labels.is_monotonic_decreasing)):\r\n",
      "                if inplace:\r\n",
      "                    return\r\n",
      "                else:\r\n",
      "                    return self.copy()\r\n",
      "\r\n",
      "            indexer = nargsort(labels, kind=kind, ascending=ascending,\r\n",
      "                               na_position=na_position)\r\n",
      "\r\n",
      "        baxis = self._get_block_manager_axis(axis)\r\n",
      "        new_data = self._data.take(indexer,\r\n",
      "                                   axis=baxis,\r\n",
      "                                   verify=False)\r\n",
      "\r\n",
      "        # reconstruct axis if needed\r\n",
      "        new_data.axes[baxis] = new_data.axes[baxis]._sort_levels_monotonic()\r\n",
      "\r\n",
      "        if inplace:\r\n",
      "            return self._update_inplace(new_data)\r\n",
      "        else:\r\n",
      "            return self._constructor(new_data).__finalize__(self)\r\n",
      "\r\n",
      "    def sortlevel(self, level=0, axis=0, ascending=True, inplace=False,\r\n",
      "                  sort_remaining=True):\r\n",
      "        \"\"\"\r\n",
      "        DEPRECATED: use :meth:`DataFrame.sort_index`\r\n",
      "\r\n",
      "        Sort multilevel index by chosen axis and primary level. Data will be\r\n",
      "        lexicographically sorted by the chosen level followed by the other\r\n",
      "        levels (in order)\r\n",
      "\r\n",
      "        Parameters\r\n",
      "        ----------\r\n",
      "        level : int\r\n",
      "        axis : {0 or 'index', 1 or 'columns'}, default 0\r\n",
      "        ascending : boolean, default True\r\n",
      "        inplace : boolean, default False\r\n",
      "            Sort the DataFrame without creating a new instance\r\n",
      "        sort_remaining : boolean, default True\r\n",
      "            Sort by the other levels too.\r\n",
      "\r\n",
      "        Returns\r\n",
      "        -------\r\n",
      "        sorted : DataFrame\r\n",
      "\r\n",
      "        See Also\r\n",
      "        --------\r\n",
      "        DataFrame.sort_index(level=...)\r\n",
      "\r\n",
      "        \"\"\"\r\n",
      "        warnings.warn(\"sortlevel is deprecated, use sort_index(level= ...)\",\r\n",
      "                      FutureWarning, stacklevel=2)\r\n",
      "        return self.sort_index(level=level, axis=axis, ascending=ascending,\r\n",
      "                               inplace=inplace, sort_remaining=sort_remaining)\r\n",
      "\r\n",
      "    def nlargest(self, n, columns, keep='first'):\r\n",
      "        \"\"\"Get the rows of a DataFrame sorted by the `n` largest\r\n",
      "        values of `columns`.\r\n",
      "\r\n",
      "        .. versionadded:: 0.17.0\r\n",
      "\r\n",
      "        Parameters\r\n",
      "        ----------\r\n",
      "        n : int\r\n",
      "            Number of items to retrieve\r\n",
      "        columns : list or str\r\n",
      "            Column name or names to order by\r\n",
      "        keep : {'first', 'last'}, default 'first'\r\n",
      "            Where there are duplicate values:\r\n",
      "            - ``first`` : take the first occurrence.\r\n",
      "            - ``last`` : take the last occurrence.\r\n",
      "\r\n",
      "        Returns\r\n",
      "        -------\r\n",
      "        DataFrame\r\n",
      "\r\n",
      "        Examples\r\n",
      "        --------\r\n",
      "        >>> df = DataFrame({'a': [1, 10, 8, 11, -1],\r\n",
      "        ...                 'b': list('abdce'),\r\n",
      "        ...                 'c': [1.0, 2.0, np.nan, 3.0, 4.0]})\r\n",
      "        >>> df.nlargest(3, 'a')\r\n",
      "            a  b   c\r\n",
      "        3  11  c   3\r\n",
      "        1  10  b   2\r\n",
      "        2   8  d NaN\r\n",
      "        \"\"\"\r\n",
      "        return algorithms.SelectNFrame(self,\r\n",
      "                                       n=n,\r\n",
      "                                       keep=keep,\r\n",
      "                                       columns=columns).nlargest()\r\n",
      "\r\n",
      "    def nsmallest(self, n, columns, keep='first'):\r\n",
      "        \"\"\"Get the rows of a DataFrame sorted by the `n` smallest\r\n",
      "        values of `columns`.\r\n",
      "\r\n",
      "        .. versionadded:: 0.17.0\r\n",
      "\r\n",
      "        Parameters\r\n",
      "        ----------\r\n",
      "        n : int\r\n",
      "            Number of items to retrieve\r\n",
      "        columns : list or str\r\n",
      "            Column name or names to order by\r\n",
      "        keep : {'first', 'last'}, default 'first'\r\n",
      "            Where there are duplicate values:\r\n",
      "            - ``first`` : take the first occurrence.\r\n",
      "            - ``last`` : take the last occurrence.\r\n",
      "\r\n",
      "        Returns\r\n",
      "        -------\r\n",
      "        DataFrame\r\n",
      "\r\n",
      "        Examples\r\n",
      "        --------\r\n",
      "        >>> df = DataFrame({'a': [1, 10, 8, 11, -1],\r\n",
      "        ...                 'b': list('abdce'),\r\n",
      "        ...                 'c': [1.0, 2.0, np.nan, 3.0, 4.0]})\r\n",
      "        >>> df.nsmallest(3, 'a')\r\n",
      "           a  b   c\r\n",
      "        4 -1  e   4\r\n",
      "        0  1  a   1\r\n",
      "        2  8  d NaN\r\n",
      "        \"\"\"\r\n",
      "        return algorithms.SelectNFrame(self,\r\n",
      "                                       n=n,\r\n",
      "                                       keep=keep,\r\n",
      "                                       columns=columns).nsmallest()\r\n",
      "\r\n",
      "    def swaplevel(self, i=-2, j=-1, axis=0):\r\n",
      "        \"\"\"\r\n",
      "        Swap levels i and j in a MultiIndex on a particular axis\r\n",
      "\r\n",
      "        Parameters\r\n",
      "        ----------\r\n",
      "        i, j : int, string (can be mixed)\r\n",
      "            Level of index to be swapped. Can pass level name as string.\r\n",
      "\r\n",
      "        Returns\r\n",
      "        -------\r\n",
      "        swapped : type of caller (new object)\r\n",
      "\r\n",
      "        .. versionchanged:: 0.18.1\r\n",
      "\r\n",
      "           The indexes ``i`` and ``j`` are now optional, and default to\r\n",
      "           the two innermost levels of the index.\r\n",
      "\r\n",
      "        \"\"\"\r\n",
      "        result = self.copy()\r\n",
      "\r\n",
      "        axis = self._get_axis_number(axis)\r\n",
      "        if axis == 0:\r\n",
      "            result.index = result.index.swaplevel(i, j)\r\n",
      "        else:\r\n",
      "            result.columns = result.columns.swaplevel(i, j)\r\n",
      "        return result\r\n",
      "\r\n",
      "    def reorder_levels(self, order, axis=0):\r\n",
      "        \"\"\"\r\n",
      "        Rearrange index levels using input order.\r\n",
      "        May not drop or duplicate levels\r\n",
      "\r\n",
      "        Parameters\r\n",
      "        ----------\r\n",
      "        order : list of int or list of str\r\n",
      "            List representing new level order. Reference level by number\r\n",
      "            (position) or by key (label).\r\n",
      "        axis : int\r\n",
      "            Where to reorder levels.\r\n",
      "\r\n",
      "        Returns\r\n",
      "        -------\r\n",
      "        type of caller (new object)\r\n",
      "        \"\"\"\r\n",
      "        axis = self._get_axis_number(axis)\r\n",
      "        if not isinstance(self._get_axis(axis),\r\n",
      "                          MultiIndex):  # pragma: no cover\r\n",
      "            raise TypeError('Can only reorder levels on a hierarchical axis.')\r\n",
      "\r\n",
      "        result = self.copy()\r\n",
      "\r\n",
      "        if axis == 0:\r\n",
      "            result.index = result.index.reorder_levels(order)\r\n",
      "        else:\r\n",
      "            result.columns = result.columns.reorder_levels(order)\r\n",
      "        return result\r\n",
      "\r\n",
      "    # ----------------------------------------------------------------------\r\n",
      "    # Arithmetic / combination related\r\n",
      "\r\n",
      "    def _combine_frame(self, other, func, fill_value=None, level=None,\r\n",
      "                       try_cast=True):\r\n",
      "        this, other = self.align(other, join='outer', level=level, copy=False)\r\n",
      "        new_index, new_columns = this.index, this.columns\r\n",
      "\r\n",
      "        def _arith_op(left, right):\r\n",
      "            if fill_value is not None:\r\n",
      "                left_mask = isna(left)\r\n",
      "                right_mask = isna(right)\r\n",
      "                left = left.copy()\r\n",
      "                right = right.copy()\r\n",
      "\r\n",
      "                # one but not both\r\n",
      "                mask = left_mask ^ right_mask\r\n",
      "                left[left_mask & mask] = fill_value\r\n",
      "                right[right_mask & mask] = fill_value\r\n",
      "\r\n",
      "            return func(left, right)\r\n",
      "\r\n",
      "        if this._is_mixed_type or other._is_mixed_type:\r\n",
      "\r\n",
      "            # unique\r\n",
      "            if this.columns.is_unique:\r\n",
      "\r\n",
      "                def f(col):\r\n",
      "                    r = _arith_op(this[col].values, other[col].values)\r\n",
      "                    return self._constructor_sliced(r, index=new_index,\r\n",
      "                                                    dtype=r.dtype)\r\n",
      "\r\n",
      "                result = dict([(col, f(col)) for col in this])\r\n",
      "\r\n",
      "            # non-unique\r\n",
      "            else:\r\n",
      "\r\n",
      "                def f(i):\r\n",
      "                    r = _arith_op(this.iloc[:, i].values,\r\n",
      "                                  other.iloc[:, i].values)\r\n",
      "                    return self._constructor_sliced(r, index=new_index,\r\n",
      "                                                    dtype=r.dtype)\r\n",
      "\r\n",
      "                result = dict([\r\n",
      "                    (i, f(i)) for i, col in enumerate(this.columns)\r\n",
      "                ])\r\n",
      "                result = self._constructor(result, index=new_index, copy=False)\r\n",
      "                result.columns = new_columns\r\n",
      "                return result\r\n",
      "\r\n",
      "        else:\r\n",
      "            result = _arith_op(this.values, other.values)\r\n",
      "\r\n",
      "        return self._constructor(result, index=new_index, columns=new_columns,\r\n",
      "                                 copy=False)\r\n",
      "\r\n",
      "    def _combine_series(self, other, func, fill_value=None, axis=None,\r\n",
      "                        level=None, try_cast=True):\r\n",
      "        if axis is not None:\r\n",
      "            axis = self._get_axis_name(axis)\r\n",
      "            if axis == 'index':\r\n",
      "                return self._combine_match_index(other, func, level=level,\r\n",
      "                                                 fill_value=fill_value,\r\n",
      "                                                 try_cast=try_cast)\r\n",
      "            else:\r\n",
      "                return self._combine_match_columns(other, func, level=level,\r\n",
      "                                                   fill_value=fill_value,\r\n",
      "                                                   try_cast=try_cast)\r\n",
      "        return self._combine_series_infer(other, func, level=level,\r\n",
      "                                          fill_value=fill_value,\r\n",
      "                                          try_cast=try_cast)\r\n",
      "\r\n",
      "    def _combine_series_infer(self, other, func, level=None,\r\n",
      "                              fill_value=None, try_cast=True):\r\n",
      "        if len(other) == 0:\r\n",
      "            return self * np.nan\r\n",
      "\r\n",
      "        if len(self) == 0:\r\n",
      "            # Ambiguous case, use _series so works with DataFrame\r\n",
      "            return self._constructor(data=self._series, index=self.index,\r\n",
      "                                     columns=self.columns)\r\n",
      "\r\n",
      "        return self._combine_match_columns(other, func, level=level,\r\n",
      "                                           fill_value=fill_value,\r\n",
      "                                           try_cast=try_cast)\r\n",
      "\r\n",
      "    def _combine_match_index(self, other, func, level=None,\r\n",
      "                             fill_value=None, try_cast=True):\r\n",
      "        left, right = self.align(other, join='outer', axis=0, level=level,\r\n",
      "                                 copy=False)\r\n",
      "        if fill_value is not None:\r\n",
      "            raise NotImplementedError(\"fill_value %r not supported.\" %\r\n",
      "                                      fill_value)\r\n",
      "        return self._constructor(func(left.values.T, right.values).T,\r\n",
      "                                 index=left.index, columns=self.columns,\r\n",
      "                                 copy=False)\r\n",
      "\r\n",
      "    def _combine_match_columns(self, other, func, level=None,\r\n",
      "                               fill_value=None, try_cast=True):\r\n",
      "        left, right = self.align(other, join='outer', axis=1, level=level,\r\n",
      "                                 copy=False)\r\n",
      "        if fill_value is not None:\r\n",
      "            raise NotImplementedError(\"fill_value %r not supported\" %\r\n",
      "                                      fill_value)\r\n",
      "\r\n",
      "        new_data = left._data.eval(func=func, other=right,\r\n",
      "                                   axes=[left.columns, self.index],\r\n",
      "                                   try_cast=try_cast)\r\n",
      "        return self._constructor(new_data)\r\n",
      "\r\n",
      "    def _combine_const(self, other, func, errors='raise', try_cast=True):\r\n",
      "        new_data = self._data.eval(func=func, other=other,\r\n",
      "                                   errors=errors,\r\n",
      "                                   try_cast=try_cast)\r\n",
      "        return self._constructor(new_data)\r\n",
      "\r\n",
      "    def _compare_frame_evaluate(self, other, func, str_rep, try_cast=True):\r\n",
      "\r\n",
      "        import pandas.core.computation.expressions as expressions\r\n",
      "        # unique\r\n",
      "        if self.columns.is_unique:\r\n",
      "\r\n",
      "            def _compare(a, b):\r\n",
      "                return dict([(col, func(a[col], b[col])) for col in a.columns])\r\n",
      "\r\n",
      "            new_data = expressions.evaluate(_compare, str_rep, self, other)\r\n",
      "            return self._constructor(data=new_data, index=self.index,\r\n",
      "                                     columns=self.columns, copy=False)\r\n",
      "        # non-unique\r\n",
      "        else:\r\n",
      "\r\n",
      "            def _compare(a, b):\r\n",
      "                return dict([(i, func(a.iloc[:, i], b.iloc[:, i]))\r\n",
      "                             for i, col in enumerate(a.columns)])\r\n",
      "\r\n",
      "            new_data = expressions.evaluate(_compare, str_rep, self, other)\r\n",
      "            result = self._constructor(data=new_data, index=self.index,\r\n",
      "                                       copy=False)\r\n",
      "            result.columns = self.columns\r\n",
      "            return result\r\n",
      "\r\n",
      "    def _compare_frame(self, other, func, str_rep, try_cast=True):\r\n",
      "        if not self._indexed_same(other):\r\n",
      "            raise ValueError('Can only compare identically-labeled '\r\n",
      "                             'DataFrame objects')\r\n",
      "        return self._compare_frame_evaluate(other, func, str_rep,\r\n",
      "                                            try_cast=try_cast)\r\n",
      "\r\n",
      "    def _flex_compare_frame(self, other, func, str_rep, level, try_cast=True):\r\n",
      "        if not self._indexed_same(other):\r\n",
      "            self, other = self.align(other, 'outer', level=level, copy=False)\r\n",
      "        return self._compare_frame_evaluate(other, func, str_rep,\r\n",
      "                                            try_cast=try_cast)\r\n",
      "\r\n",
      "    def combine(self, other, func, fill_value=None, overwrite=True):\r\n",
      "        \"\"\"\r\n",
      "        Add two DataFrame objects and do not propagate NaN values, so if for a\r\n",
      "        (column, time) one frame is missing a value, it will default to the\r\n",
      "        other frame's value (which might be NaN as well)\r\n",
      "\r\n",
      "        Parameters\r\n",
      "        ----------\r\n",
      "        other : DataFrame\r\n",
      "        func : function\r\n",
      "            Function that takes two series as inputs and return a Series or a\r\n",
      "            scalar\r\n",
      "        fill_value : scalar value\r\n",
      "        overwrite : boolean, default True\r\n",
      "            If True then overwrite values for common keys in the calling frame\r\n",
      "\r\n",
      "        Returns\r\n",
      "        -------\r\n",
      "        result : DataFrame\r\n",
      "\r\n",
      "        Examples\r\n",
      "        --------\r\n",
      "        >>> df1 = DataFrame({'A': [0, 0], 'B': [4, 4]})\r\n",
      "        >>> df2 = DataFrame({'A': [1, 1], 'B': [3, 3]})\r\n",
      "        >>> df1.combine(df2, lambda s1, s2: s1 if s1.sum() < s2.sum() else s2)\r\n",
      "           A  B\r\n",
      "        0  0  3\r\n",
      "        1  0  3\r\n",
      "\r\n",
      "        See Also\r\n",
      "        --------\r\n",
      "        DataFrame.combine_first : Combine two DataFrame objects and default to\r\n",
      "            non-null values in frame calling the method\r\n",
      "        \"\"\"\r\n",
      "        other_idxlen = len(other.index)  # save for compare\r\n",
      "\r\n",
      "        this, other = self.align(other, copy=False)\r\n",
      "        new_index = this.index\r\n",
      "\r\n",
      "        if other.empty and len(new_index) == len(self.index):\r\n",
      "            return self.copy()\r\n",
      "\r\n",
      "        if self.empty and len(other) == other_idxlen:\r\n",
      "            return other.copy()\r\n",
      "\r\n",
      "        # sorts if possible\r\n",
      "        new_columns = this.columns.union(other.columns)\r\n",
      "        do_fill = fill_value is not None\r\n",
      "\r\n",
      "        result = {}\r\n",
      "        for col in new_columns:\r\n",
      "            series = this[col]\r\n",
      "            otherSeries = other[col]\r\n",
      "\r\n",
      "            this_dtype = series.dtype\r\n",
      "            other_dtype = otherSeries.dtype\r\n",
      "\r\n",
      "            this_mask = isna(series)\r\n",
      "            other_mask = isna(otherSeries)\r\n",
      "\r\n",
      "            # don't overwrite columns unecessarily\r\n",
      "            # DO propagate if this column is not in the intersection\r\n",
      "            if not overwrite and other_mask.all():\r\n",
      "                result[col] = this[col].copy()\r\n",
      "                continue\r\n",
      "\r\n",
      "            if do_fill:\r\n",
      "                series = series.copy()\r\n",
      "                otherSeries = otherSeries.copy()\r\n",
      "                series[this_mask] = fill_value\r\n",
      "                otherSeries[other_mask] = fill_value\r\n",
      "\r\n",
      "            # if we have different dtypes, possibily promote\r\n",
      "            new_dtype = this_dtype\r\n",
      "            if not is_dtype_equal(this_dtype, other_dtype):\r\n",
      "                new_dtype = find_common_type([this_dtype, other_dtype])\r\n",
      "                if not is_dtype_equal(this_dtype, new_dtype):\r\n",
      "                    series = series.astype(new_dtype)\r\n",
      "                if not is_dtype_equal(other_dtype, new_dtype):\r\n",
      "                    otherSeries = otherSeries.astype(new_dtype)\r\n",
      "\r\n",
      "            # see if we need to be represented as i8 (datetimelike)\r\n",
      "            # try to keep us at this dtype\r\n",
      "            needs_i8_conversion_i = needs_i8_conversion(new_dtype)\r\n",
      "            if needs_i8_conversion_i:\r\n",
      "                arr = func(series, otherSeries, True)\r\n",
      "            else:\r\n",
      "                arr = func(series, otherSeries)\r\n",
      "\r\n",
      "            if do_fill:\r\n",
      "                arr = _ensure_float(arr)\r\n",
      "                arr[this_mask & other_mask] = np.nan\r\n",
      "\r\n",
      "            # try to downcast back to the original dtype\r\n",
      "            if needs_i8_conversion_i:\r\n",
      "                # ToDo: This conversion should be handled in\r\n",
      "                # _maybe_cast_to_datetime but the change affects lot...\r\n",
      "                if is_datetime64tz_dtype(new_dtype):\r\n",
      "                    arr = DatetimeIndex._simple_new(arr, tz=new_dtype.tz)\r\n",
      "                else:\r\n",
      "                    arr = maybe_cast_to_datetime(arr, new_dtype)\r\n",
      "            else:\r\n",
      "                arr = maybe_downcast_to_dtype(arr, this_dtype)\r\n",
      "\r\n",
      "            result[col] = arr\r\n",
      "\r\n",
      "        # convert_objects just in case\r\n",
      "        return self._constructor(result, index=new_index,\r\n",
      "                                 columns=new_columns)._convert(datetime=True,\r\n",
      "                                                               copy=False)\r\n",
      "\r\n",
      "    def combine_first(self, other):\r\n",
      "        \"\"\"\r\n",
      "        Combine two DataFrame objects and default to non-null values in frame\r\n",
      "        calling the method. Result index columns will be the union of the\r\n",
      "        respective indexes and columns\r\n",
      "\r\n",
      "        Parameters\r\n",
      "        ----------\r\n",
      "        other : DataFrame\r\n",
      "\r\n",
      "        Returns\r\n",
      "        -------\r\n",
      "        combined : DataFrame\r\n",
      "\r\n",
      "        Examples\r\n",
      "        --------\r\n",
      "        df1's values prioritized, use values from df2 to fill holes:\r\n",
      "\r\n",
      "        >>> df1 = pd.DataFrame([[1, np.nan]])\r\n",
      "        >>> df2 = pd.DataFrame([[3, 4]])\r\n",
      "        >>> df1.combine_first(df2)\r\n",
      "           0    1\r\n",
      "        0  1  4.0\r\n",
      "\r\n",
      "        See Also\r\n",
      "        --------\r\n",
      "        DataFrame.combine : Perform series-wise operation on two DataFrames\r\n",
      "            using a given function\r\n",
      "        \"\"\"\r\n",
      "        import pandas.core.computation.expressions as expressions\r\n",
      "\r\n",
      "        def combiner(x, y, needs_i8_conversion=False):\r\n",
      "            x_values = x.values if hasattr(x, 'values') else x\r\n",
      "            y_values = y.values if hasattr(y, 'values') else y\r\n",
      "            if needs_i8_conversion:\r\n",
      "                mask = isna(x)\r\n",
      "                x_values = x_values.view('i8')\r\n",
      "                y_values = y_values.view('i8')\r\n",
      "            else:\r\n",
      "                mask = isna(x_values)\r\n",
      "\r\n",
      "            return expressions.where(mask, y_values, x_values)\r\n",
      "\r\n",
      "        return self.combine(other, combiner, overwrite=False)\r\n",
      "\r\n",
      "    def update(self, other, join='left', overwrite=True, filter_func=None,\r\n",
      "               raise_conflict=False):\r\n",
      "        \"\"\"\r\n",
      "        Modify DataFrame in place using non-NA values from passed\r\n",
      "        DataFrame. Aligns on indices\r\n",
      "\r\n",
      "        Parameters\r\n",
      "        ----------\r\n",
      "        other : DataFrame, or object coercible into a DataFrame\r\n",
      "        join : {'left'}, default 'left'\r\n",
      "        overwrite : boolean, default True\r\n",
      "            If True then overwrite values for common keys in the calling frame\r\n",
      "        filter_func : callable(1d-array) -> 1d-array<boolean>, default None\r\n",
      "            Can choose to replace values other than NA. Return True for values\r\n",
      "            that should be updated\r\n",
      "        raise_conflict : boolean\r\n",
      "            If True, will raise an error if the DataFrame and other both\r\n",
      "            contain data in the same place.\r\n",
      "\r\n",
      "        Examples\r\n",
      "        --------\r\n",
      "        >>> df = pd.DataFrame({'A': [1, 2, 3],\r\n",
      "        ...                    'B': [400, 500, 600]})\r\n",
      "        >>> new_df = pd.DataFrame({'B': [4, 5, 6],\r\n",
      "        ...                        'C': [7, 8, 9]})\r\n",
      "        >>> df.update(new_df)\r\n",
      "        >>> df\r\n",
      "           A  B\r\n",
      "        0  1  4\r\n",
      "        1  2  5\r\n",
      "        2  3  6\r\n",
      "\r\n",
      "        >>> df = pd.DataFrame({'A': ['a', 'b', 'c'],\r\n",
      "        ...                    'B': ['x', 'y', 'z']})\r\n",
      "        >>> new_df = pd.DataFrame({'B': ['d', 'e', 'f', 'g', 'h', 'i']})\r\n",
      "        >>> df.update(new_df)\r\n",
      "        >>> df\r\n",
      "           A  B\r\n",
      "        0  a  d\r\n",
      "        1  b  e\r\n",
      "        2  c  f\r\n",
      "\r\n",
      "        >>> df = pd.DataFrame({'A': ['a', 'b', 'c'],\r\n",
      "        ...                    'B': ['x', 'y', 'z']})\r\n",
      "        >>> new_column = pd.Series(['d', 'e'], name='B', index=[0, 2])\r\n",
      "        >>> df.update(new_column)\r\n",
      "        >>> df\r\n",
      "           A  B\r\n",
      "        0  a  d\r\n",
      "        1  b  y\r\n",
      "        2  c  e\r\n",
      "        >>> df = pd.DataFrame({'A': ['a', 'b', 'c'],\r\n",
      "        ...                    'B': ['x', 'y', 'z']})\r\n",
      "        >>> new_df = pd.DataFrame({'B': ['d', 'e']}, index=[1, 2])\r\n",
      "        >>> df.update(new_df)\r\n",
      "        >>> df\r\n",
      "           A  B\r\n",
      "        0  a  x\r\n",
      "        1  b  d\r\n",
      "        2  c  e\r\n",
      "\r\n",
      "        If ``other`` contains NaNs the corresponding values are not updated\r\n",
      "        in the original dataframe.\r\n",
      "\r\n",
      "        >>> df = pd.DataFrame({'A': [1, 2, 3],\r\n",
      "        ...                    'B': [400, 500, 600]})\r\n",
      "        >>> new_df = pd.DataFrame({'B': [4, np.nan, 6]})\r\n",
      "        >>> df.update(new_df)\r\n",
      "        >>> df\r\n",
      "           A      B\r\n",
      "        0  1    4.0\r\n",
      "        1  2  500.0\r\n",
      "        2  3    6.0\r\n",
      "        \"\"\"\r\n",
      "        import pandas.core.computation.expressions as expressions\r\n",
      "        # TODO: Support other joins\r\n",
      "        if join != 'left':  # pragma: no cover\r\n",
      "            raise NotImplementedError(\"Only left join is supported\")\r\n",
      "\r\n",
      "        if not isinstance(other, DataFrame):\r\n",
      "            other = DataFrame(other)\r\n",
      "\r\n",
      "        other = other.reindex_like(self)\r\n",
      "\r\n",
      "        for col in self.columns:\r\n",
      "            this = self[col].values\r\n",
      "            that = other[col].values\r\n",
      "            if filter_func is not None:\r\n",
      "                with np.errstate(all='ignore'):\r\n",
      "                    mask = ~filter_func(this) | isna(that)\r\n",
      "            else:\r\n",
      "                if raise_conflict:\r\n",
      "                    mask_this = notna(that)\r\n",
      "                    mask_that = notna(this)\r\n",
      "                    if any(mask_this & mask_that):\r\n",
      "                        raise ValueError(\"Data overlaps.\")\r\n",
      "\r\n",
      "                if overwrite:\r\n",
      "                    mask = isna(that)\r\n",
      "                else:\r\n",
      "                    mask = notna(this)\r\n",
      "\r\n",
      "            # don't overwrite columns unecessarily\r\n",
      "            if mask.all():\r\n",
      "                continue\r\n",
      "\r\n",
      "            self[col] = expressions.where(mask, this, that)\r\n",
      "\r\n",
      "    # ----------------------------------------------------------------------\r\n",
      "    # Misc methods\r\n",
      "\r\n",
      "    def _get_valid_indices(self):\r\n",
      "        is_valid = self.count(1) > 0\r\n",
      "        return self.index[is_valid]\r\n",
      "\r\n",
      "    @Appender(_shared_docs['valid_index'] % {\r\n",
      "        'position': 'first', 'klass': 'DataFrame'})\r\n",
      "    def first_valid_index(self):\r\n",
      "        if len(self) == 0:\r\n",
      "            return None\r\n",
      "\r\n",
      "        valid_indices = self._get_valid_indices()\r\n",
      "        return valid_indices[0] if len(valid_indices) else None\r\n",
      "\r\n",
      "    @Appender(_shared_docs['valid_index'] % {\r\n",
      "        'position': 'last', 'klass': 'DataFrame'})\r\n",
      "    def last_valid_index(self):\r\n",
      "        if len(self) == 0:\r\n",
      "            return None\r\n",
      "\r\n",
      "        valid_indices = self._get_valid_indices()\r\n",
      "        return valid_indices[-1] if len(valid_indices) else None\r\n",
      "\r\n",
      "    # ----------------------------------------------------------------------\r\n",
      "    # Data reshaping\r\n",
      "\r\n",
      "    def pivot(self, index=None, columns=None, values=None):\r\n",
      "        \"\"\"\r\n",
      "        Reshape data (produce a \"pivot\" table) based on column values. Uses\r\n",
      "        unique values from index / columns to form axes of the resulting\r\n",
      "        DataFrame.\r\n",
      "\r\n",
      "        Parameters\r\n",
      "        ----------\r\n",
      "        index : string or object, optional\r\n",
      "            Column name to use to make new frame's index. If None, uses\r\n",
      "            existing index.\r\n",
      "        columns : string or object\r\n",
      "            Column name to use to make new frame's columns\r\n",
      "        values : string or object, optional\r\n",
      "            Column name to use for populating new frame's values. If not\r\n",
      "            specified, all remaining columns will be used and the result will\r\n",
      "            have hierarchically indexed columns\r\n",
      "\r\n",
      "        Returns\r\n",
      "        -------\r\n",
      "        pivoted : DataFrame\r\n",
      "\r\n",
      "        See also\r\n",
      "        --------\r\n",
      "        DataFrame.pivot_table : generalization of pivot that can handle\r\n",
      "            duplicate values for one index/column pair\r\n",
      "        DataFrame.unstack : pivot based on the index values instead of a\r\n",
      "            column\r\n",
      "\r\n",
      "        Notes\r\n",
      "        -----\r\n",
      "        For finer-tuned control, see hierarchical indexing documentation along\r\n",
      "        with the related stack/unstack methods\r\n",
      "\r\n",
      "        Examples\r\n",
      "        --------\r\n",
      "\r\n",
      "        >>> df = pd.DataFrame({'foo': ['one','one','one','two','two','two'],\r\n",
      "                               'bar': ['A', 'B', 'C', 'A', 'B', 'C'],\r\n",
      "                               'baz': [1, 2, 3, 4, 5, 6]})\r\n",
      "        >>> df\r\n",
      "            foo   bar  baz\r\n",
      "        0   one   A    1\r\n",
      "        1   one   B    2\r\n",
      "        2   one   C    3\r\n",
      "        3   two   A    4\r\n",
      "        4   two   B    5\r\n",
      "        5   two   C    6\r\n",
      "\r\n",
      "        >>> df.pivot(index='foo', columns='bar', values='baz')\r\n",
      "             A   B   C\r\n",
      "        one  1   2   3\r\n",
      "        two  4   5   6\r\n",
      "\r\n",
      "        >>> df.pivot(index='foo', columns='bar')['baz']\r\n",
      "             A   B   C\r\n",
      "        one  1   2   3\r\n",
      "        two  4   5   6\r\n",
      "\r\n",
      "\r\n",
      "        \"\"\"\r\n",
      "        from pandas.core.reshape.reshape import pivot\r\n",
      "        return pivot(self, index=index, columns=columns, values=values)\r\n",
      "\r\n",
      "    _shared_docs['pivot_table'] = \"\"\"\r\n",
      "        Create a spreadsheet-style pivot table as a DataFrame. The levels in\r\n",
      "        the pivot table will be stored in MultiIndex objects (hierarchical\r\n",
      "        indexes) on the index and columns of the result DataFrame\r\n",
      "\r\n",
      "        Parameters\r\n",
      "        ----------%s\r\n",
      "        values : column to aggregate, optional\r\n",
      "        index : column, Grouper, array, or list of the previous\r\n",
      "            If an array is passed, it must be the same length as the data. The\r\n",
      "            list can contain any of the other types (except list).\r\n",
      "            Keys to group by on the pivot table index.  If an array is passed,\r\n",
      "            it is being used as the same manner as column values.\r\n",
      "        columns : column, Grouper, array, or list of the previous\r\n",
      "            If an array is passed, it must be the same length as the data. The\r\n",
      "            list can contain any of the other types (except list).\r\n",
      "            Keys to group by on the pivot table column.  If an array is passed,\r\n",
      "            it is being used as the same manner as column values.\r\n",
      "        aggfunc : function or list of functions, default numpy.mean\r\n",
      "            If list of functions passed, the resulting pivot table will have\r\n",
      "            hierarchical columns whose top level are the function names\r\n",
      "            (inferred from the function objects themselves)\r\n",
      "        fill_value : scalar, default None\r\n",
      "            Value to replace missing values with\r\n",
      "        margins : boolean, default False\r\n",
      "            Add all row / columns (e.g. for subtotal / grand totals)\r\n",
      "        dropna : boolean, default True\r\n",
      "            Do not include columns whose entries are all NaN\r\n",
      "        margins_name : string, default 'All'\r\n",
      "            Name of the row / column that will contain the totals\r\n",
      "            when margins is True.\r\n",
      "\r\n",
      "        Examples\r\n",
      "        --------\r\n",
      "        >>> df = pd.DataFrame({\"A\": [\"foo\", \"foo\", \"foo\", \"foo\", \"foo\",\r\n",
      "        ...                          \"bar\", \"bar\", \"bar\", \"bar\"],\r\n",
      "        ...                    \"B\": [\"one\", \"one\", \"one\", \"two\", \"two\",\r\n",
      "        ...                          \"one\", \"one\", \"two\", \"two\"],\r\n",
      "        ...                    \"C\": [\"small\", \"large\", \"large\", \"small\",\r\n",
      "        ...                          \"small\", \"large\", \"small\", \"small\",\r\n",
      "        ...                          \"large\"],\r\n",
      "        ...                    \"D\": [1, 2, 2, 3, 3, 4, 5, 6, 7]})\r\n",
      "        >>> df\r\n",
      "             A    B      C  D\r\n",
      "        0  foo  one  small  1\r\n",
      "        1  foo  one  large  2\r\n",
      "        2  foo  one  large  2\r\n",
      "        3  foo  two  small  3\r\n",
      "        4  foo  two  small  3\r\n",
      "        5  bar  one  large  4\r\n",
      "        6  bar  one  small  5\r\n",
      "        7  bar  two  small  6\r\n",
      "        8  bar  two  large  7\r\n",
      "\r\n",
      "        >>> table = pivot_table(df, values='D', index=['A', 'B'],\r\n",
      "        ...                     columns=['C'], aggfunc=np.sum)\r\n",
      "        >>> table\r\n",
      "        ... # doctest: +NORMALIZE_WHITESPACE\r\n",
      "        C        large  small\r\n",
      "        A   B\r\n",
      "        bar one    4.0    5.0\r\n",
      "            two    7.0    6.0\r\n",
      "        foo one    4.0    1.0\r\n",
      "            two    NaN    6.0\r\n",
      "\r\n",
      "        Returns\r\n",
      "        -------\r\n",
      "        table : DataFrame\r\n",
      "\r\n",
      "        See also\r\n",
      "        --------\r\n",
      "        DataFrame.pivot : pivot without aggregation that can handle\r\n",
      "            non-numeric data\r\n",
      "        \"\"\"\r\n",
      "\r\n",
      "    @Substitution('')\r\n",
      "    @Appender(_shared_docs['pivot_table'])\r\n",
      "    def pivot_table(self, values=None, index=None, columns=None,\r\n",
      "                    aggfunc='mean', fill_value=None, margins=False,\r\n",
      "                    dropna=True, margins_name='All'):\r\n",
      "        from pandas.core.reshape.pivot import pivot_table\r\n",
      "        return pivot_table(self, values=values, index=index, columns=columns,\r\n",
      "                           aggfunc=aggfunc, fill_value=fill_value,\r\n",
      "                           margins=margins, dropna=dropna,\r\n",
      "                           margins_name=margins_name)\r\n",
      "\r\n",
      "    def stack(self, level=-1, dropna=True):\r\n",
      "        \"\"\"\r\n",
      "        Pivot a level of the (possibly hierarchical) column labels, returning a\r\n",
      "        DataFrame (or Series in the case of an object with a single level of\r\n",
      "        column labels) having a hierarchical index with a new inner-most level\r\n",
      "        of row labels.\r\n",
      "        The level involved will automatically get sorted.\r\n",
      "\r\n",
      "        Parameters\r\n",
      "        ----------\r\n",
      "        level : int, string, or list of these, default last level\r\n",
      "            Level(s) to stack, can pass level name\r\n",
      "        dropna : boolean, default True\r\n",
      "            Whether to drop rows in the resulting Frame/Series with no valid\r\n",
      "            values\r\n",
      "\r\n",
      "        Examples\r\n",
      "        ----------\r\n",
      "        >>> s\r\n",
      "             a   b\r\n",
      "        one  1.  2.\r\n",
      "        two  3.  4.\r\n",
      "\r\n",
      "        >>> s.stack()\r\n",
      "        one a    1\r\n",
      "            b    2\r\n",
      "        two a    3\r\n",
      "            b    4\r\n",
      "\r\n",
      "        Returns\r\n",
      "        -------\r\n",
      "        stacked : DataFrame or Series\r\n",
      "        \"\"\"\r\n",
      "        from pandas.core.reshape.reshape import stack, stack_multiple\r\n",
      "\r\n",
      "        if isinstance(level, (tuple, list)):\r\n",
      "            return stack_multiple(self, level, dropna=dropna)\r\n",
      "        else:\r\n",
      "            return stack(self, level, dropna=dropna)\r\n",
      "\r\n",
      "    def unstack(self, level=-1, fill_value=None):\r\n",
      "        \"\"\"\r\n",
      "        Pivot a level of the (necessarily hierarchical) index labels, returning\r\n",
      "        a DataFrame having a new level of column labels whose inner-most level\r\n",
      "        consists of the pivoted index labels. If the index is not a MultiIndex,\r\n",
      "        the output will be a Series (the analogue of stack when the columns are\r\n",
      "        not a MultiIndex).\r\n",
      "        The level involved will automatically get sorted.\r\n",
      "\r\n",
      "        Parameters\r\n",
      "        ----------\r\n",
      "        level : int, string, or list of these, default -1 (last level)\r\n",
      "            Level(s) of index to unstack, can pass level name\r\n",
      "        fill_value : replace NaN with this value if the unstack produces\r\n",
      "            missing values\r\n",
      "\r\n",
      "            .. versionadded: 0.18.0\r\n",
      "\r\n",
      "        See also\r\n",
      "        --------\r\n",
      "        DataFrame.pivot : Pivot a table based on column values.\r\n",
      "        DataFrame.stack : Pivot a level of the column labels (inverse operation\r\n",
      "            from `unstack`).\r\n",
      "\r\n",
      "        Examples\r\n",
      "        --------\r\n",
      "        >>> index = pd.MultiIndex.from_tuples([('one', 'a'), ('one', 'b'),\r\n",
      "        ...                                    ('two', 'a'), ('two', 'b')])\r\n",
      "        >>> s = pd.Series(np.arange(1.0, 5.0), index=index)\r\n",
      "        >>> s\r\n",
      "        one  a   1.0\r\n",
      "             b   2.0\r\n",
      "        two  a   3.0\r\n",
      "             b   4.0\r\n",
      "        dtype: float64\r\n",
      "\r\n",
      "        >>> s.unstack(level=-1)\r\n",
      "             a   b\r\n",
      "        one  1.0  2.0\r\n",
      "        two  3.0  4.0\r\n",
      "\r\n",
      "        >>> s.unstack(level=0)\r\n",
      "           one  two\r\n",
      "        a  1.0   3.0\r\n",
      "        b  2.0   4.0\r\n",
      "\r\n",
      "        >>> df = s.unstack(level=0)\r\n",
      "        >>> df.unstack()\r\n",
      "        one  a  1.0\r\n",
      "             b  2.0\r\n",
      "        two  a  3.0\r\n",
      "             b  4.0\r\n",
      "        dtype: float64\r\n",
      "\r\n",
      "        Returns\r\n",
      "        -------\r\n",
      "        unstacked : DataFrame or Series\r\n",
      "        \"\"\"\r\n",
      "        from pandas.core.reshape.reshape import unstack\r\n",
      "        return unstack(self, level, fill_value)\r\n",
      "\r\n",
      "    _shared_docs['melt'] = (\"\"\"\r\n",
      "    \"Unpivots\" a DataFrame from wide format to long format, optionally\r\n",
      "    leaving identifier variables set.\r\n",
      "\r\n",
      "    This function is useful to massage a DataFrame into a format where one\r\n",
      "    or more columns are identifier variables (`id_vars`), while all other\r\n",
      "    columns, considered measured variables (`value_vars`), are \"unpivoted\" to\r\n",
      "    the row axis, leaving just two non-identifier columns, 'variable' and\r\n",
      "    'value'.\r\n",
      "\r\n",
      "    %(versionadded)s\r\n",
      "    Parameters\r\n",
      "    ----------\r\n",
      "    frame : DataFrame\r\n",
      "    id_vars : tuple, list, or ndarray, optional\r\n",
      "        Column(s) to use as identifier variables.\r\n",
      "    value_vars : tuple, list, or ndarray, optional\r\n",
      "        Column(s) to unpivot. If not specified, uses all columns that\r\n",
      "        are not set as `id_vars`.\r\n",
      "    var_name : scalar\r\n",
      "        Name to use for the 'variable' column. If None it uses\r\n",
      "        ``frame.columns.name`` or 'variable'.\r\n",
      "    value_name : scalar, default 'value'\r\n",
      "        Name to use for the 'value' column.\r\n",
      "    col_level : int or string, optional\r\n",
      "        If columns are a MultiIndex then use this level to melt.\r\n",
      "\r\n",
      "    See also\r\n",
      "    --------\r\n",
      "    %(other)s\r\n",
      "    pivot_table\r\n",
      "    DataFrame.pivot\r\n",
      "\r\n",
      "    Examples\r\n",
      "    --------\r\n",
      "    >>> import pandas as pd\r\n",
      "    >>> df = pd.DataFrame({'A': {0: 'a', 1: 'b', 2: 'c'},\r\n",
      "    ...                    'B': {0: 1, 1: 3, 2: 5},\r\n",
      "    ...                    'C': {0: 2, 1: 4, 2: 6}})\r\n",
      "    >>> df\r\n",
      "       A  B  C\r\n",
      "    0  a  1  2\r\n",
      "    1  b  3  4\r\n",
      "    2  c  5  6\r\n",
      "\r\n",
      "    >>> %(caller)sid_vars=['A'], value_vars=['B'])\r\n",
      "       A variable  value\r\n",
      "    0  a        B      1\r\n",
      "    1  b        B      3\r\n",
      "    2  c        B      5\r\n",
      "\r\n",
      "    >>> %(caller)sid_vars=['A'], value_vars=['B', 'C'])\r\n",
      "       A variable  value\r\n",
      "    0  a        B      1\r\n",
      "    1  b        B      3\r\n",
      "    2  c        B      5\r\n",
      "    3  a        C      2\r\n",
      "    4  b        C      4\r\n",
      "    5  c        C      6\r\n",
      "\r\n",
      "    The names of 'variable' and 'value' columns can be customized:\r\n",
      "\r\n",
      "    >>> %(caller)sid_vars=['A'], value_vars=['B'],\r\n",
      "    ...         var_name='myVarname', value_name='myValname')\r\n",
      "       A myVarname  myValname\r\n",
      "    0  a         B          1\r\n",
      "    1  b         B          3\r\n",
      "    2  c         B          5\r\n",
      "\r\n",
      "    If you have multi-index columns:\r\n",
      "\r\n",
      "    >>> df.columns = [list('ABC'), list('DEF')]\r\n",
      "    >>> df\r\n",
      "       A  B  C\r\n",
      "       D  E  F\r\n",
      "    0  a  1  2\r\n",
      "    1  b  3  4\r\n",
      "    2  c  5  6\r\n",
      "\r\n",
      "    >>> %(caller)scol_level=0, id_vars=['A'], value_vars=['B'])\r\n",
      "       A variable  value\r\n",
      "    0  a        B      1\r\n",
      "    1  b        B      3\r\n",
      "    2  c        B      5\r\n",
      "\r\n",
      "    >>> %(caller)sid_vars=[('A', 'D')], value_vars=[('B', 'E')])\r\n",
      "      (A, D) variable_0 variable_1  value\r\n",
      "    0      a          B          E      1\r\n",
      "    1      b          B          E      3\r\n",
      "    2      c          B          E      5\r\n",
      "\r\n",
      "    \"\"\")\r\n",
      "\r\n",
      "    @Appender(_shared_docs['melt'] %\r\n",
      "              dict(caller='df.melt(',\r\n",
      "                   versionadded='.. versionadded:: 0.20.0\\n',\r\n",
      "                   other='melt'))\r\n",
      "    def melt(self, id_vars=None, value_vars=None, var_name=None,\r\n",
      "             value_name='value', col_level=None):\r\n",
      "        from pandas.core.reshape.reshape import melt\r\n",
      "        return melt(self, id_vars=id_vars, value_vars=value_vars,\r\n",
      "                    var_name=var_name, value_name=value_name,\r\n",
      "                    col_level=col_level)\r\n",
      "\r\n",
      "    # ----------------------------------------------------------------------\r\n",
      "    # Time series-related\r\n",
      "\r\n",
      "    def diff(self, periods=1, axis=0):\r\n",
      "        \"\"\"\r\n",
      "        1st discrete difference of object\r\n",
      "\r\n",
      "        Parameters\r\n",
      "        ----------\r\n",
      "        periods : int, default 1\r\n",
      "            Periods to shift for forming difference\r\n",
      "        axis : {0 or 'index', 1 or 'columns'}, default 0\r\n",
      "            Take difference over rows (0) or columns (1).\r\n",
      "\r\n",
      "            .. versionadded: 0.16.1\r\n",
      "\r\n",
      "        Returns\r\n",
      "        -------\r\n",
      "        diffed : DataFrame\r\n",
      "        \"\"\"\r\n",
      "        bm_axis = self._get_block_manager_axis(axis)\r\n",
      "        new_data = self._data.diff(n=periods, axis=bm_axis)\r\n",
      "        return self._constructor(new_data)\r\n",
      "\r\n",
      "    # ----------------------------------------------------------------------\r\n",
      "    # Function application\r\n",
      "\r\n",
      "    def _gotitem(self, key, ndim, subset=None):\r\n",
      "        \"\"\"\r\n",
      "        sub-classes to define\r\n",
      "        return a sliced object\r\n",
      "\r\n",
      "        Parameters\r\n",
      "        ----------\r\n",
      "        key : string / list of selections\r\n",
      "        ndim : 1,2\r\n",
      "            requested ndim of result\r\n",
      "        subset : object, default None\r\n",
      "            subset to act on\r\n",
      "        \"\"\"\r\n",
      "        if subset is None:\r\n",
      "            subset = self\r\n",
      "\r\n",
      "        # TODO: _shallow_copy(subset)?\r\n",
      "        return self[key]\r\n",
      "\r\n",
      "    _agg_doc = dedent(\"\"\"\r\n",
      "    Examples\r\n",
      "    --------\r\n",
      "\r\n",
      "    >>> df = pd.DataFrame(np.random.randn(10, 3), columns=['A', 'B', 'C'],\r\n",
      "    ...                   index=pd.date_range('1/1/2000', periods=10))\r\n",
      "    >>> df.iloc[3:7] = np.nan\r\n",
      "\r\n",
      "    Aggregate these functions across all columns\r\n",
      "\r\n",
      "    >>> df.agg(['sum', 'min'])\r\n",
      "                A         B         C\r\n",
      "    sum -0.182253 -0.614014 -2.909534\r\n",
      "    min -1.916563 -1.460076 -1.568297\r\n",
      "\r\n",
      "    Different aggregations per column\r\n",
      "\r\n",
      "    >>> df.agg({'A' : ['sum', 'min'], 'B' : ['min', 'max']})\r\n",
      "                A         B\r\n",
      "    max       NaN  1.514318\r\n",
      "    min -1.916563 -1.460076\r\n",
      "    sum -0.182253       NaN\r\n",
      "\r\n",
      "    See also\r\n",
      "    --------\r\n",
      "    pandas.DataFrame.apply\r\n",
      "    pandas.DataFrame.transform\r\n",
      "    pandas.DataFrame.groupby.aggregate\r\n",
      "    pandas.DataFrame.resample.aggregate\r\n",
      "    pandas.DataFrame.rolling.aggregate\r\n",
      "\r\n",
      "    \"\"\")\r\n",
      "\r\n",
      "    @Appender(_agg_doc)\r\n",
      "    @Appender(_shared_docs['aggregate'] % dict(\r\n",
      "        versionadded='.. versionadded:: 0.20.0',\r\n",
      "        **_shared_doc_kwargs))\r\n",
      "    def aggregate(self, func, axis=0, *args, **kwargs):\r\n",
      "        axis = self._get_axis_number(axis)\r\n",
      "\r\n",
      "        # TODO: flipped axis\r\n",
      "        result = None\r\n",
      "        if axis == 0:\r\n",
      "            try:\r\n",
      "                result, how = self._aggregate(func, axis=0, *args, **kwargs)\r\n",
      "            except TypeError:\r\n",
      "                pass\r\n",
      "        if result is None:\r\n",
      "            return self.apply(func, axis=axis, args=args, **kwargs)\r\n",
      "        return result\r\n",
      "\r\n",
      "    agg = aggregate\r\n",
      "\r\n",
      "    def apply(self, func, axis=0, broadcast=False, raw=False, reduce=None,\r\n",
      "              args=(), **kwds):\r\n",
      "        \"\"\"\r\n",
      "        Applies function along input axis of DataFrame.\r\n",
      "\r\n",
      "        Objects passed to functions are Series objects having index\r\n",
      "        either the DataFrame's index (axis=0) or the columns (axis=1).\r\n",
      "        Return type depends on whether passed function aggregates, or the\r\n",
      "        reduce argument if the DataFrame is empty.\r\n",
      "\r\n",
      "        Parameters\r\n",
      "        ----------\r\n",
      "        func : function\r\n",
      "            Function to apply to each column/row\r\n",
      "        axis : {0 or 'index', 1 or 'columns'}, default 0\r\n",
      "            * 0 or 'index': apply function to each column\r\n",
      "            * 1 or 'columns': apply function to each row\r\n",
      "        broadcast : boolean, default False\r\n",
      "            For aggregation functions, return object of same size with values\r\n",
      "            propagated\r\n",
      "        raw : boolean, default False\r\n",
      "            If False, convert each row or column into a Series. If raw=True the\r\n",
      "            passed function will receive ndarray objects instead. If you are\r\n",
      "            just applying a NumPy reduction function this will achieve much\r\n",
      "            better performance\r\n",
      "        reduce : boolean or None, default None\r\n",
      "            Try to apply reduction procedures. If the DataFrame is empty,\r\n",
      "            apply will use reduce to determine whether the result should be a\r\n",
      "            Series or a DataFrame. If reduce is None (the default), apply's\r\n",
      "            return value will be guessed by calling func an empty Series (note:\r\n",
      "            while guessing, exceptions raised by func will be ignored). If\r\n",
      "            reduce is True a Series will always be returned, and if False a\r\n",
      "            DataFrame will always be returned.\r\n",
      "        args : tuple\r\n",
      "            Positional arguments to pass to function in addition to the\r\n",
      "            array/series\r\n",
      "        Additional keyword arguments will be passed as keywords to the function\r\n",
      "\r\n",
      "        Notes\r\n",
      "        -----\r\n",
      "        In the current implementation apply calls func twice on the\r\n",
      "        first column/row to decide whether it can take a fast or slow\r\n",
      "        code path. This can lead to unexpected behavior if func has\r\n",
      "        side-effects, as they will take effect twice for the first\r\n",
      "        column/row.\r\n",
      "\r\n",
      "        Examples\r\n",
      "        --------\r\n",
      "        >>> df.apply(numpy.sqrt) # returns DataFrame\r\n",
      "        >>> df.apply(numpy.sum, axis=0) # equiv to df.sum(0)\r\n",
      "        >>> df.apply(numpy.sum, axis=1) # equiv to df.sum(1)\r\n",
      "\r\n",
      "        See also\r\n",
      "        --------\r\n",
      "        DataFrame.applymap: For elementwise operations\r\n",
      "        DataFrame.aggregate: only perform aggregating type operations\r\n",
      "        DataFrame.transform: only perform transformating type operations\r\n",
      "\r\n",
      "        Returns\r\n",
      "        -------\r\n",
      "        applied : Series or DataFrame\r\n",
      "        \"\"\"\r\n",
      "        axis = self._get_axis_number(axis)\r\n",
      "        ignore_failures = kwds.pop('ignore_failures', False)\r\n",
      "\r\n",
      "        # dispatch to agg\r\n",
      "        if axis == 0 and isinstance(func, (list, dict)):\r\n",
      "            return self.aggregate(func, axis=axis, *args, **kwds)\r\n",
      "\r\n",
      "        if len(self.columns) == 0 and len(self.index) == 0:\r\n",
      "            return self._apply_empty_result(func, axis, reduce, *args, **kwds)\r\n",
      "\r\n",
      "        # if we are a string, try to dispatch\r\n",
      "        if isinstance(func, compat.string_types):\r\n",
      "            if axis:\r\n",
      "                kwds['axis'] = axis\r\n",
      "            return getattr(self, func)(*args, **kwds)\r\n",
      "\r\n",
      "        if kwds or args and not isinstance(func, np.ufunc):\r\n",
      "            def f(x):\r\n",
      "                return func(x, *args, **kwds)\r\n",
      "        else:\r\n",
      "            f = func\r\n",
      "\r\n",
      "        if isinstance(f, np.ufunc):\r\n",
      "            with np.errstate(all='ignore'):\r\n",
      "                results = f(self.values)\r\n",
      "            return self._constructor(data=results, index=self.index,\r\n",
      "                                     columns=self.columns, copy=False)\r\n",
      "        else:\r\n",
      "            if not broadcast:\r\n",
      "                if not all(self.shape):\r\n",
      "                    return self._apply_empty_result(func, axis, reduce, *args,\r\n",
      "                                                    **kwds)\r\n",
      "\r\n",
      "                if raw and not self._is_mixed_type:\r\n",
      "                    return self._apply_raw(f, axis)\r\n",
      "                else:\r\n",
      "                    if reduce is None:\r\n",
      "                        reduce = True\r\n",
      "                    return self._apply_standard(\r\n",
      "                        f, axis,\r\n",
      "                        reduce=reduce,\r\n",
      "                        ignore_failures=ignore_failures)\r\n",
      "            else:\r\n",
      "                return self._apply_broadcast(f, axis)\r\n",
      "\r\n",
      "    def _apply_empty_result(self, func, axis, reduce, *args, **kwds):\r\n",
      "        if reduce is None:\r\n",
      "            reduce = False\r\n",
      "            try:\r\n",
      "                reduce = not isinstance(func(_EMPTY_SERIES, *args, **kwds),\r\n",
      "                                        Series)\r\n",
      "            except Exception:\r\n",
      "                pass\r\n",
      "\r\n",
      "        if reduce:\r\n",
      "            return Series(np.nan, index=self._get_agg_axis(axis))\r\n",
      "        else:\r\n",
      "            return self.copy()\r\n",
      "\r\n",
      "    def _apply_raw(self, func, axis):\r\n",
      "        try:\r\n",
      "            result = lib.reduce(self.values, func, axis=axis)\r\n",
      "        except Exception:\r\n",
      "            result = np.apply_along_axis(func, axis, self.values)\r\n",
      "\r\n",
      "        # TODO: mixed type case\r\n",
      "        if result.ndim == 2:\r\n",
      "            return DataFrame(result, index=self.index, columns=self.columns)\r\n",
      "        else:\r\n",
      "            return Series(result, index=self._get_agg_axis(axis))\r\n",
      "\r\n",
      "    def _apply_standard(self, func, axis, ignore_failures=False, reduce=True):\r\n",
      "\r\n",
      "        # skip if we are mixed datelike and trying reduce across axes\r\n",
      "        # GH6125\r\n",
      "        if (reduce and axis == 1 and self._is_mixed_type and\r\n",
      "                self._is_datelike_mixed_type):\r\n",
      "            reduce = False\r\n",
      "\r\n",
      "        # try to reduce first (by default)\r\n",
      "        # this only matters if the reduction in values is of different dtype\r\n",
      "        # e.g. if we want to apply to a SparseFrame, then can't directly reduce\r\n",
      "        if reduce:\r\n",
      "            values = self.values\r\n",
      "\r\n",
      "            # we cannot reduce using non-numpy dtypes,\r\n",
      "            # as demonstrated in gh-12244\r\n",
      "            if not is_extension_type(values):\r\n",
      "                # Create a dummy Series from an empty array\r\n",
      "                index = self._get_axis(axis)\r\n",
      "                empty_arr = np.empty(len(index), dtype=values.dtype)\r\n",
      "                dummy = Series(empty_arr, index=self._get_axis(axis),\r\n",
      "                               dtype=values.dtype)\r\n",
      "\r\n",
      "                try:\r\n",
      "                    labels = self._get_agg_axis(axis)\r\n",
      "                    result = lib.reduce(values, func, axis=axis, dummy=dummy,\r\n",
      "                                        labels=labels)\r\n",
      "                    return Series(result, index=labels)\r\n",
      "                except Exception:\r\n",
      "                    pass\r\n",
      "\r\n",
      "        dtype = object if self._is_mixed_type else None\r\n",
      "        if axis == 0:\r\n",
      "            series_gen = (self._ixs(i, axis=1)\r\n",
      "                          for i in range(len(self.columns)))\r\n",
      "            res_index = self.columns\r\n",
      "            res_columns = self.index\r\n",
      "        elif axis == 1:\r\n",
      "            res_index = self.index\r\n",
      "            res_columns = self.columns\r\n",
      "            values = self.values\r\n",
      "            series_gen = (Series.from_array(arr, index=res_columns, name=name,\r\n",
      "                                            dtype=dtype)\r\n",
      "                          for i, (arr, name) in enumerate(zip(values,\r\n",
      "                                                              res_index)))\r\n",
      "        else:  # pragma : no cover\r\n",
      "            raise AssertionError('Axis must be 0 or 1, got %s' % str(axis))\r\n",
      "\r\n",
      "        i = None\r\n",
      "        keys = []\r\n",
      "        results = {}\r\n",
      "        if ignore_failures:\r\n",
      "            successes = []\r\n",
      "            for i, v in enumerate(series_gen):\r\n",
      "                try:\r\n",
      "                    results[i] = func(v)\r\n",
      "                    keys.append(v.name)\r\n",
      "                    successes.append(i)\r\n",
      "                except Exception:\r\n",
      "                    pass\r\n",
      "            # so will work with MultiIndex\r\n",
      "            if len(successes) < len(res_index):\r\n",
      "                res_index = res_index.take(successes)\r\n",
      "        else:\r\n",
      "            try:\r\n",
      "                for i, v in enumerate(series_gen):\r\n",
      "                    results[i] = func(v)\r\n",
      "                    keys.append(v.name)\r\n",
      "            except Exception as e:\r\n",
      "                if hasattr(e, 'args'):\r\n",
      "                    # make sure i is defined\r\n",
      "                    if i is not None:\r\n",
      "                        k = res_index[i]\r\n",
      "                        e.args = e.args + ('occurred at index %s' %\r\n",
      "                                           pprint_thing(k), )\r\n",
      "                raise\r\n",
      "\r\n",
      "        if len(results) > 0 and is_sequence(results[0]):\r\n",
      "            if not isinstance(results[0], Series):\r\n",
      "                index = res_columns\r\n",
      "            else:\r\n",
      "                index = None\r\n",
      "\r\n",
      "            result = self._constructor(data=results, index=index)\r\n",
      "            result.columns = res_index\r\n",
      "\r\n",
      "            if axis == 1:\r\n",
      "                result = result.T\r\n",
      "            result = result._convert(datetime=True, timedelta=True, copy=False)\r\n",
      "\r\n",
      "        else:\r\n",
      "\r\n",
      "            result = Series(results)\r\n",
      "            result.index = res_index\r\n",
      "\r\n",
      "        return result\r\n",
      "\r\n",
      "    def _apply_broadcast(self, func, axis):\r\n",
      "        if axis == 0:\r\n",
      "            target = self\r\n",
      "        elif axis == 1:\r\n",
      "            target = self.T\r\n",
      "        else:  # pragma: no cover\r\n",
      "            raise AssertionError('Axis must be 0 or 1, got %s' % axis)\r\n",
      "\r\n",
      "        result_values = np.empty_like(target.values)\r\n",
      "        columns = target.columns\r\n",
      "        for i, col in enumerate(columns):\r\n",
      "            result_values[:, i] = func(target[col])\r\n",
      "\r\n",
      "        result = self._constructor(result_values, index=target.index,\r\n",
      "                                   columns=target.columns)\r\n",
      "\r\n",
      "        if axis == 1:\r\n",
      "            result = result.T\r\n",
      "\r\n",
      "        return result\r\n",
      "\r\n",
      "    def applymap(self, func):\r\n",
      "        \"\"\"\r\n",
      "        Apply a function to a DataFrame that is intended to operate\r\n",
      "        elementwise, i.e. like doing map(func, series) for each series in the\r\n",
      "        DataFrame\r\n",
      "\r\n",
      "        Parameters\r\n",
      "        ----------\r\n",
      "        func : function\r\n",
      "            Python function, returns a single value from a single value\r\n",
      "\r\n",
      "        Examples\r\n",
      "        --------\r\n",
      "\r\n",
      "        >>> df = pd.DataFrame(np.random.randn(3, 3))\r\n",
      "        >>> df\r\n",
      "            0         1          2\r\n",
      "        0  -0.029638  1.081563   1.280300\r\n",
      "        1   0.647747  0.831136  -1.549481\r\n",
      "        2   0.513416 -0.884417   0.195343\r\n",
      "        >>> df = df.applymap(lambda x: '%.2f' % x)\r\n",
      "        >>> df\r\n",
      "            0         1          2\r\n",
      "        0  -0.03      1.08       1.28\r\n",
      "        1   0.65      0.83      -1.55\r\n",
      "        2   0.51     -0.88       0.20\r\n",
      "\r\n",
      "        Returns\r\n",
      "        -------\r\n",
      "        applied : DataFrame\r\n",
      "\r\n",
      "        See also\r\n",
      "        --------\r\n",
      "        DataFrame.apply : For operations on rows/columns\r\n",
      "\r\n",
      "        \"\"\"\r\n",
      "\r\n",
      "        # if we have a dtype == 'M8[ns]', provide boxed values\r\n",
      "        def infer(x):\r\n",
      "            if x.empty:\r\n",
      "                return lib.map_infer(x, func)\r\n",
      "            return lib.map_infer(x.asobject, func)\r\n",
      "\r\n",
      "        return self.apply(infer)\r\n",
      "\r\n",
      "    # ----------------------------------------------------------------------\r\n",
      "    # Merging / joining methods\r\n",
      "\r\n",
      "    def append(self, other, ignore_index=False, verify_integrity=False):\r\n",
      "        \"\"\"\r\n",
      "        Append rows of `other` to the end of this frame, returning a new\r\n",
      "        object. Columns not in this frame are added as new columns.\r\n",
      "\r\n",
      "        Parameters\r\n",
      "        ----------\r\n",
      "        other : DataFrame or Series/dict-like object, or list of these\r\n",
      "            The data to append.\r\n",
      "        ignore_index : boolean, default False\r\n",
      "            If True, do not use the index labels.\r\n",
      "        verify_integrity : boolean, default False\r\n",
      "            If True, raise ValueError on creating index with duplicates.\r\n",
      "\r\n",
      "        Returns\r\n",
      "        -------\r\n",
      "        appended : DataFrame\r\n",
      "\r\n",
      "        Notes\r\n",
      "        -----\r\n",
      "        If a list of dict/series is passed and the keys are all contained in\r\n",
      "        the DataFrame's index, the order of the columns in the resulting\r\n",
      "        DataFrame will be unchanged.\r\n",
      "\r\n",
      "        Iteratively appending rows to a DataFrame can be more computationally\r\n",
      "        intensive than a single concatenate. A better solution is to append\r\n",
      "        those rows to a list and then concatenate the list with the original\r\n",
      "        DataFrame all at once.\r\n",
      "\r\n",
      "        See also\r\n",
      "        --------\r\n",
      "        pandas.concat : General function to concatenate DataFrame, Series\r\n",
      "            or Panel objects\r\n",
      "\r\n",
      "        Examples\r\n",
      "        --------\r\n",
      "\r\n",
      "        >>> df = pd.DataFrame([[1, 2], [3, 4]], columns=list('AB'))\r\n",
      "        >>> df\r\n",
      "           A  B\r\n",
      "        0  1  2\r\n",
      "        1  3  4\r\n",
      "        >>> df2 = pd.DataFrame([[5, 6], [7, 8]], columns=list('AB'))\r\n",
      "        >>> df.append(df2)\r\n",
      "           A  B\r\n",
      "        0  1  2\r\n",
      "        1  3  4\r\n",
      "        0  5  6\r\n",
      "        1  7  8\r\n",
      "\r\n",
      "        With `ignore_index` set to True:\r\n",
      "\r\n",
      "        >>> df.append(df2, ignore_index=True)\r\n",
      "           A  B\r\n",
      "        0  1  2\r\n",
      "        1  3  4\r\n",
      "        2  5  6\r\n",
      "        3  7  8\r\n",
      "\r\n",
      "        The following, while not recommended methods for generating DataFrames,\r\n",
      "        show two ways to generate a DataFrame from multiple data sources.\r\n",
      "\r\n",
      "        Less efficient:\r\n",
      "\r\n",
      "        >>> df = pd.DataFrame(columns=['A'])\r\n",
      "        >>> for i in range(5):\r\n",
      "        ...     df = df.append({'A': i}, ignore_index=True)\r\n",
      "        >>> df\r\n",
      "           A\r\n",
      "        0  0\r\n",
      "        1  1\r\n",
      "        2  2\r\n",
      "        3  3\r\n",
      "        4  4\r\n",
      "\r\n",
      "        More efficient:\r\n",
      "\r\n",
      "        >>> pd.concat([pd.DataFrame([i], columns=['A']) for i in range(5)],\r\n",
      "        ...           ignore_index=True)\r\n",
      "           A\r\n",
      "        0  0\r\n",
      "        1  1\r\n",
      "        2  2\r\n",
      "        3  3\r\n",
      "        4  4\r\n",
      "\r\n",
      "        \"\"\"\r\n",
      "        if isinstance(other, (Series, dict)):\r\n",
      "            if isinstance(other, dict):\r\n",
      "                other = Series(other)\r\n",
      "            if other.name is None and not ignore_index:\r\n",
      "                raise TypeError('Can only append a Series if ignore_index=True'\r\n",
      "                                ' or if the Series has a name')\r\n",
      "\r\n",
      "            if other.name is None:\r\n",
      "                index = None\r\n",
      "            else:\r\n",
      "                # other must have the same index name as self, otherwise\r\n",
      "                # index name will be reset\r\n",
      "                index = Index([other.name], name=self.index.name)\r\n",
      "\r\n",
      "            combined_columns = self.columns.tolist() + self.columns.union(\r\n",
      "                other.index).difference(self.columns).tolist()\r\n",
      "            other = other.reindex(combined_columns, copy=False)\r\n",
      "            other = DataFrame(other.values.reshape((1, len(other))),\r\n",
      "                              index=index,\r\n",
      "                              columns=combined_columns)\r\n",
      "            other = other._convert(datetime=True, timedelta=True)\r\n",
      "            if not self.columns.equals(combined_columns):\r\n",
      "                self = self.reindex(columns=combined_columns)\r\n",
      "        elif isinstance(other, list) and not isinstance(other[0], DataFrame):\r\n",
      "            other = DataFrame(other)\r\n",
      "            if (self.columns.get_indexer(other.columns) >= 0).all():\r\n",
      "                other = other.loc[:, self.columns]\r\n",
      "\r\n",
      "        from pandas.core.reshape.concat import concat\r\n",
      "        if isinstance(other, (list, tuple)):\r\n",
      "            to_concat = [self] + other\r\n",
      "        else:\r\n",
      "            to_concat = [self, other]\r\n",
      "        return concat(to_concat, ignore_index=ignore_index,\r\n",
      "                      verify_integrity=verify_integrity)\r\n",
      "\r\n",
      "    def join(self, other, on=None, how='left', lsuffix='', rsuffix='',\r\n",
      "             sort=False):\r\n",
      "        \"\"\"\r\n",
      "        Join columns with other DataFrame either on index or on a key\r\n",
      "        column. Efficiently Join multiple DataFrame objects by index at once by\r\n",
      "        passing a list.\r\n",
      "\r\n",
      "        Parameters\r\n",
      "        ----------\r\n",
      "        other : DataFrame, Series with name field set, or list of DataFrame\r\n",
      "            Index should be similar to one of the columns in this one. If a\r\n",
      "            Series is passed, its name attribute must be set, and that will be\r\n",
      "            used as the column name in the resulting joined DataFrame\r\n",
      "        on : column name, tuple/list of column names, or array-like\r\n",
      "            Column(s) in the caller to join on the index in other,\r\n",
      "            otherwise joins index-on-index. If multiples\r\n",
      "            columns given, the passed DataFrame must have a MultiIndex. Can\r\n",
      "            pass an array as the join key if not already contained in the\r\n",
      "            calling DataFrame. Like an Excel VLOOKUP operation\r\n",
      "        how : {'left', 'right', 'outer', 'inner'}, default: 'left'\r\n",
      "            How to handle the operation of the two objects.\r\n",
      "\r\n",
      "            * left: use calling frame's index (or column if on is specified)\r\n",
      "            * right: use other frame's index\r\n",
      "            * outer: form union of calling frame's index (or column if on is\r\n",
      "              specified) with other frame's index, and sort it\r\n",
      "              lexicographically\r\n",
      "            * inner: form intersection of calling frame's index (or column if\r\n",
      "              on is specified) with other frame's index, preserving the order\r\n",
      "              of the calling's one\r\n",
      "        lsuffix : string\r\n",
      "            Suffix to use from left frame's overlapping columns\r\n",
      "        rsuffix : string\r\n",
      "            Suffix to use from right frame's overlapping columns\r\n",
      "        sort : boolean, default False\r\n",
      "            Order result DataFrame lexicographically by the join key. If False,\r\n",
      "            the order of the join key depends on the join type (how keyword)\r\n",
      "\r\n",
      "        Notes\r\n",
      "        -----\r\n",
      "        on, lsuffix, and rsuffix options are not supported when passing a list\r\n",
      "        of DataFrame objects\r\n",
      "\r\n",
      "        Examples\r\n",
      "        --------\r\n",
      "        >>> caller = pd.DataFrame({'key': ['K0', 'K1', 'K2', 'K3', 'K4', 'K5'],\r\n",
      "        ...                        'A': ['A0', 'A1', 'A2', 'A3', 'A4', 'A5']})\r\n",
      "\r\n",
      "        >>> caller\r\n",
      "            A key\r\n",
      "        0  A0  K0\r\n",
      "        1  A1  K1\r\n",
      "        2  A2  K2\r\n",
      "        3  A3  K3\r\n",
      "        4  A4  K4\r\n",
      "        5  A5  K5\r\n",
      "\r\n",
      "        >>> other = pd.DataFrame({'key': ['K0', 'K1', 'K2'],\r\n",
      "        ...                       'B': ['B0', 'B1', 'B2']})\r\n",
      "\r\n",
      "        >>> other\r\n",
      "            B key\r\n",
      "        0  B0  K0\r\n",
      "        1  B1  K1\r\n",
      "        2  B2  K2\r\n",
      "\r\n",
      "        Join DataFrames using their indexes.\r\n",
      "\r\n",
      "        >>> caller.join(other, lsuffix='_caller', rsuffix='_other')\r\n",
      "\r\n",
      "        >>>     A key_caller    B key_other\r\n",
      "            0  A0         K0   B0        K0\r\n",
      "            1  A1         K1   B1        K1\r\n",
      "            2  A2         K2   B2        K2\r\n",
      "            3  A3         K3  NaN       NaN\r\n",
      "            4  A4         K4  NaN       NaN\r\n",
      "            5  A5         K5  NaN       NaN\r\n",
      "\r\n",
      "\r\n",
      "        If we want to join using the key columns, we need to set key to be\r\n",
      "        the index in both caller and other. The joined DataFrame will have\r\n",
      "        key as its index.\r\n",
      "\r\n",
      "        >>> caller.set_index('key').join(other.set_index('key'))\r\n",
      "\r\n",
      "        >>>      A    B\r\n",
      "            key\r\n",
      "            K0   A0   B0\r\n",
      "            K1   A1   B1\r\n",
      "            K2   A2   B2\r\n",
      "            K3   A3  NaN\r\n",
      "            K4   A4  NaN\r\n",
      "            K5   A5  NaN\r\n",
      "\r\n",
      "        Another option to join using the key columns is to use the on\r\n",
      "        parameter. DataFrame.join always uses other's index but we can use any\r\n",
      "        column in the caller. This method preserves the original caller's\r\n",
      "        index in the result.\r\n",
      "\r\n",
      "        >>> caller.join(other.set_index('key'), on='key')\r\n",
      "\r\n",
      "        >>>     A key    B\r\n",
      "            0  A0  K0   B0\r\n",
      "            1  A1  K1   B1\r\n",
      "            2  A2  K2   B2\r\n",
      "            3  A3  K3  NaN\r\n",
      "            4  A4  K4  NaN\r\n",
      "            5  A5  K5  NaN\r\n",
      "\r\n",
      "\r\n",
      "        See also\r\n",
      "        --------\r\n",
      "        DataFrame.merge : For column(s)-on-columns(s) operations\r\n",
      "\r\n",
      "        Returns\r\n",
      "        -------\r\n",
      "        joined : DataFrame\r\n",
      "        \"\"\"\r\n",
      "        # For SparseDataFrame's benefit\r\n",
      "        return self._join_compat(other, on=on, how=how, lsuffix=lsuffix,\r\n",
      "                                 rsuffix=rsuffix, sort=sort)\r\n",
      "\r\n",
      "    def _join_compat(self, other, on=None, how='left', lsuffix='', rsuffix='',\r\n",
      "                     sort=False):\r\n",
      "        from pandas.core.reshape.merge import merge\r\n",
      "        from pandas.core.reshape.concat import concat\r\n",
      "\r\n",
      "        if isinstance(other, Series):\r\n",
      "            if other.name is None:\r\n",
      "                raise ValueError('Other Series must have a name')\r\n",
      "            other = DataFrame({other.name: other})\r\n",
      "\r\n",
      "        if isinstance(other, DataFrame):\r\n",
      "            return merge(self, other, left_on=on, how=how,\r\n",
      "                         left_index=on is None, right_index=True,\r\n",
      "                         suffixes=(lsuffix, rsuffix), sort=sort)\r\n",
      "        else:\r\n",
      "            if on is not None:\r\n",
      "                raise ValueError('Joining multiple DataFrames only supported'\r\n",
      "                                 ' for joining on index')\r\n",
      "\r\n",
      "            # join indexes only using concat\r\n",
      "            if how == 'left':\r\n",
      "                how = 'outer'\r\n",
      "                join_axes = [self.index]\r\n",
      "            else:\r\n",
      "                join_axes = None\r\n",
      "\r\n",
      "            frames = [self] + list(other)\r\n",
      "\r\n",
      "            can_concat = all(df.index.is_unique for df in frames)\r\n",
      "\r\n",
      "            if can_concat:\r\n",
      "                return concat(frames, axis=1, join=how, join_axes=join_axes,\r\n",
      "                              verify_integrity=True)\r\n",
      "\r\n",
      "            joined = frames[0]\r\n",
      "\r\n",
      "            for frame in frames[1:]:\r\n",
      "                joined = merge(joined, frame, how=how, left_index=True,\r\n",
      "                               right_index=True)\r\n",
      "\r\n",
      "            return joined\r\n",
      "\r\n",
      "    @Substitution('')\r\n",
      "    @Appender(_merge_doc, indents=2)\r\n",
      "    def merge(self, right, how='inner', on=None, left_on=None, right_on=None,\r\n",
      "              left_index=False, right_index=False, sort=False,\r\n",
      "              suffixes=('_x', '_y'), copy=True, indicator=False,\r\n",
      "              validate=None):\r\n",
      "        from pandas.core.reshape.merge import merge\r\n",
      "        return merge(self, right, how=how, on=on, left_on=left_on,\r\n",
      "                     right_on=right_on, left_index=left_index,\r\n",
      "                     right_index=right_index, sort=sort, suffixes=suffixes,\r\n",
      "                     copy=copy, indicator=indicator, validate=validate)\r\n",
      "\r\n",
      "    def round(self, decimals=0, *args, **kwargs):\r\n",
      "        \"\"\"\r\n",
      "        Round a DataFrame to a variable number of decimal places.\r\n",
      "\r\n",
      "        .. versionadded:: 0.17.0\r\n",
      "\r\n",
      "        Parameters\r\n",
      "        ----------\r\n",
      "        decimals : int, dict, Series\r\n",
      "            Number of decimal places to round each column to. If an int is\r\n",
      "            given, round each column to the same number of places.\r\n",
      "            Otherwise dict and Series round to variable numbers of places.\r\n",
      "            Column names should be in the keys if `decimals` is a\r\n",
      "            dict-like, or in the index if `decimals` is a Series. Any\r\n",
      "            columns not included in `decimals` will be left as is. Elements\r\n",
      "            of `decimals` which are not columns of the input will be\r\n",
      "            ignored.\r\n",
      "\r\n",
      "        Examples\r\n",
      "        --------\r\n",
      "        >>> df = pd.DataFrame(np.random.random([3, 3]),\r\n",
      "        ...     columns=['A', 'B', 'C'], index=['first', 'second', 'third'])\r\n",
      "        >>> df\r\n",
      "                       A         B         C\r\n",
      "        first   0.028208  0.992815  0.173891\r\n",
      "        second  0.038683  0.645646  0.577595\r\n",
      "        third   0.877076  0.149370  0.491027\r\n",
      "        >>> df.round(2)\r\n",
      "                   A     B     C\r\n",
      "        first   0.03  0.99  0.17\r\n",
      "        second  0.04  0.65  0.58\r\n",
      "        third   0.88  0.15  0.49\r\n",
      "        >>> df.round({'A': 1, 'C': 2})\r\n",
      "                  A         B     C\r\n",
      "        first   0.0  0.992815  0.17\r\n",
      "        second  0.0  0.645646  0.58\r\n",
      "        third   0.9  0.149370  0.49\r\n",
      "        >>> decimals = pd.Series([1, 0, 2], index=['A', 'B', 'C'])\r\n",
      "        >>> df.round(decimals)\r\n",
      "                  A  B     C\r\n",
      "        first   0.0  1  0.17\r\n",
      "        second  0.0  1  0.58\r\n",
      "        third   0.9  0  0.49\r\n",
      "\r\n",
      "        Returns\r\n",
      "        -------\r\n",
      "        DataFrame object\r\n",
      "\r\n",
      "        See Also\r\n",
      "        --------\r\n",
      "        numpy.around\r\n",
      "        Series.round\r\n",
      "\r\n",
      "        \"\"\"\r\n",
      "        from pandas.core.reshape.concat import concat\r\n",
      "\r\n",
      "        def _dict_round(df, decimals):\r\n",
      "            for col, vals in df.iteritems():\r\n",
      "                try:\r\n",
      "                    yield _series_round(vals, decimals[col])\r\n",
      "                except KeyError:\r\n",
      "                    yield vals\r\n",
      "\r\n",
      "        def _series_round(s, decimals):\r\n",
      "            if is_integer_dtype(s) or is_float_dtype(s):\r\n",
      "                return s.round(decimals)\r\n",
      "            return s\r\n",
      "\r\n",
      "        nv.validate_round(args, kwargs)\r\n",
      "\r\n",
      "        if isinstance(decimals, (dict, Series)):\r\n",
      "            if isinstance(decimals, Series):\r\n",
      "                if not decimals.index.is_unique:\r\n",
      "                    raise ValueError(\"Index of decimals must be unique\")\r\n",
      "            new_cols = [col for col in _dict_round(self, decimals)]\r\n",
      "        elif is_integer(decimals):\r\n",
      "            # Dispatch to Series.round\r\n",
      "            new_cols = [_series_round(v, decimals)\r\n",
      "                        for _, v in self.iteritems()]\r\n",
      "        else:\r\n",
      "            raise TypeError(\"decimals must be an integer, a dict-like or a \"\r\n",
      "                            \"Series\")\r\n",
      "\r\n",
      "        if len(new_cols) > 0:\r\n",
      "            return self._constructor(concat(new_cols, axis=1),\r\n",
      "                                     index=self.index,\r\n",
      "                                     columns=self.columns)\r\n",
      "        else:\r\n",
      "            return self\r\n",
      "\r\n",
      "    # ----------------------------------------------------------------------\r\n",
      "    # Statistical methods, etc.\r\n",
      "\r\n",
      "    def corr(self, method='pearson', min_periods=1):\r\n",
      "        \"\"\"\r\n",
      "        Compute pairwise correlation of columns, excluding NA/null values\r\n",
      "\r\n",
      "        Parameters\r\n",
      "        ----------\r\n",
      "        method : {'pearson', 'kendall', 'spearman'}\r\n",
      "            * pearson : standard correlation coefficient\r",
      "\r\n",
      "            * kendall : Kendall Tau correlation coefficient\r\n",
      "            * spearman : Spearman rank correlation\r\n",
      "        min_periods : int, optional\r\n",
      "            Minimum number of observations required per pair of columns\r\n",
      "            to have a valid result. Currently only available for pearson\r\n",
      "            and spearman correlation\r\n",
      "\r\n",
      "        Returns\r\n",
      "        -------\r\n",
      "        y : DataFrame\r\n",
      "        \"\"\"\r\n",
      "        numeric_df = self._get_numeric_data()\r\n",
      "        cols = numeric_df.columns\r\n",
      "        idx = cols.copy()\r\n",
      "        mat = numeric_df.values\r\n",
      "\r\n",
      "        if method == 'pearson':\r\n",
      "            correl = libalgos.nancorr(_ensure_float64(mat), minp=min_periods)\r\n",
      "        elif method == 'spearman':\r\n",
      "            correl = libalgos.nancorr_spearman(_ensure_float64(mat),\r\n",
      "                                               minp=min_periods)\r\n",
      "        else:\r\n",
      "            if min_periods is None:\r\n",
      "                min_periods = 1\r\n",
      "            mat = _ensure_float64(mat).T\r\n",
      "            corrf = nanops.get_corr_func(method)\r\n",
      "            K = len(cols)\r\n",
      "            correl = np.empty((K, K), dtype=float)\r\n",
      "            mask = np.isfinite(mat)\r\n",
      "            for i, ac in enumerate(mat):\r\n",
      "                for j, bc in enumerate(mat):\r\n",
      "                    if i > j:\r\n",
      "                        continue\r\n",
      "\r\n",
      "                    valid = mask[i] & mask[j]\r\n",
      "                    if valid.sum() < min_periods:\r\n",
      "                        c = np.nan\r\n",
      "                    elif i == j:\r\n",
      "                        c = 1.\r\n",
      "                    elif not valid.all():\r\n",
      "                        c = corrf(ac[valid], bc[valid])\r\n",
      "                    else:\r\n",
      "                        c = corrf(ac, bc)\r\n",
      "                    correl[i, j] = c\r\n",
      "                    correl[j, i] = c\r\n",
      "\r\n",
      "        return self._constructor(correl, index=idx, columns=cols)\r\n",
      "\r\n",
      "    def cov(self, min_periods=None):\r\n",
      "        \"\"\"\r\n",
      "        Compute pairwise covariance of columns, excluding NA/null values\r\n",
      "\r\n",
      "        Parameters\r\n",
      "        ----------\r\n",
      "        min_periods : int, optional\r\n",
      "            Minimum number of observations required per pair of columns\r\n",
      "            to have a valid result.\r\n",
      "\r\n",
      "        Returns\r\n",
      "        -------\r\n",
      "        y : DataFrame\r\n",
      "\r\n",
      "        Notes\r\n",
      "        -----\r\n",
      "        `y` contains the covariance matrix of the DataFrame's time series.\r\n",
      "        The covariance is normalized by N-1 (unbiased estimator).\r\n",
      "        \"\"\"\r\n",
      "        numeric_df = self._get_numeric_data()\r\n",
      "        cols = numeric_df.columns\r\n",
      "        idx = cols.copy()\r\n",
      "        mat = numeric_df.values\r\n",
      "\r\n",
      "        if notna(mat).all():\r\n",
      "            if min_periods is not None and min_periods > len(mat):\r\n",
      "                baseCov = np.empty((mat.shape[1], mat.shape[1]))\r\n",
      "                baseCov.fill(np.nan)\r\n",
      "            else:\r\n",
      "                baseCov = np.cov(mat.T)\r\n",
      "            baseCov = baseCov.reshape((len(cols), len(cols)))\r\n",
      "        else:\r\n",
      "            baseCov = libalgos.nancorr(_ensure_float64(mat), cov=True,\r\n",
      "                                       minp=min_periods)\r\n",
      "\r\n",
      "        return self._constructor(baseCov, index=idx, columns=cols)\r\n",
      "\r\n",
      "    def corrwith(self, other, axis=0, drop=False):\r\n",
      "        \"\"\"\r\n",
      "        Compute pairwise correlation between rows or columns of two DataFrame\r\n",
      "        objects.\r\n",
      "\r\n",
      "        Parameters\r\n",
      "        ----------\r\n",
      "        other : DataFrame\r\n",
      "        axis : {0 or 'index', 1 or 'columns'}, default 0\r\n",
      "            0 or 'index' to compute column-wise, 1 or 'columns' for row-wise\r\n",
      "        drop : boolean, default False\r\n",
      "            Drop missing indices from result, default returns union of all\r\n",
      "\r\n",
      "        Returns\r\n",
      "        -------\r\n",
      "        correls : Series\r\n",
      "        \"\"\"\r\n",
      "        axis = self._get_axis_number(axis)\r\n",
      "        if isinstance(other, Series):\r\n",
      "            return self.apply(other.corr, axis=axis)\r\n",
      "\r\n",
      "        this = self._get_numeric_data()\r\n",
      "        other = other._get_numeric_data()\r\n",
      "\r\n",
      "        left, right = this.align(other, join='inner', copy=False)\r\n",
      "\r\n",
      "        # mask missing values\r\n",
      "        left = left + right * 0\r\n",
      "        right = right + left * 0\r\n",
      "\r\n",
      "        if axis == 1:\r\n",
      "            left = left.T\r\n",
      "            right = right.T\r\n",
      "\r\n",
      "        # demeaned data\r\n",
      "        ldem = left - left.mean()\r\n",
      "        rdem = right - right.mean()\r\n",
      "\r\n",
      "        num = (ldem * rdem).sum()\r\n",
      "        dom = (left.count() - 1) * left.std() * right.std()\r\n",
      "\r\n",
      "        correl = num / dom\r\n",
      "\r\n",
      "        if not drop:\r\n",
      "            raxis = 1 if axis == 0 else 0\r\n",
      "            result_index = this._get_axis(raxis).union(other._get_axis(raxis))\r\n",
      "            correl = correl.reindex(result_index)\r\n",
      "\r\n",
      "        return correl\r\n",
      "\r\n",
      "    # ----------------------------------------------------------------------\r\n",
      "    # ndarray-like stats methods\r\n",
      "\r\n",
      "    def count(self, axis=0, level=None, numeric_only=False):\r\n",
      "        \"\"\"\r\n",
      "        Return Series with number of non-NA/null observations over requested\r\n",
      "        axis. Works with non-floating point data as well (detects NaN and None)\r\n",
      "\r\n",
      "        Parameters\r\n",
      "        ----------\r\n",
      "        axis : {0 or 'index', 1 or 'columns'}, default 0\r\n",
      "            0 or 'index' for row-wise, 1 or 'columns' for column-wise\r\n",
      "        level : int or level name, default None\r\n",
      "            If the axis is a MultiIndex (hierarchical), count along a\r\n",
      "            particular level, collapsing into a DataFrame\r\n",
      "        numeric_only : boolean, default False\r\n",
      "            Include only float, int, boolean data\r\n",
      "\r\n",
      "        Returns\r\n",
      "        -------\r\n",
      "        count : Series (or DataFrame if level specified)\r\n",
      "        \"\"\"\r\n",
      "        axis = self._get_axis_number(axis)\r\n",
      "        if level is not None:\r\n",
      "            return self._count_level(level, axis=axis,\r\n",
      "                                     numeric_only=numeric_only)\r\n",
      "\r\n",
      "        if numeric_only:\r\n",
      "            frame = self._get_numeric_data()\r\n",
      "        else:\r\n",
      "            frame = self\r\n",
      "\r\n",
      "        # GH #423\r\n",
      "        if len(frame._get_axis(axis)) == 0:\r\n",
      "            result = Series(0, index=frame._get_agg_axis(axis))\r\n",
      "        else:\r\n",
      "            if frame._is_mixed_type:\r\n",
      "                result = notna(frame).sum(axis=axis)\r\n",
      "            else:\r\n",
      "                counts = notna(frame.values).sum(axis=axis)\r\n",
      "                result = Series(counts, index=frame._get_agg_axis(axis))\r\n",
      "\r\n",
      "        return result.astype('int64')\r\n",
      "\r\n",
      "    def _count_level(self, level, axis=0, numeric_only=False):\r\n",
      "        if numeric_only:\r\n",
      "            frame = self._get_numeric_data()\r\n",
      "        else:\r\n",
      "            frame = self\r\n",
      "\r\n",
      "        count_axis = frame._get_axis(axis)\r\n",
      "        agg_axis = frame._get_agg_axis(axis)\r\n",
      "\r\n",
      "        if not isinstance(count_axis, MultiIndex):\r\n",
      "            raise TypeError(\"Can only count levels on hierarchical %s.\" %\r\n",
      "                            self._get_axis_name(axis))\r\n",
      "\r\n",
      "        if frame._is_mixed_type:\r\n",
      "            # Since we have mixed types, calling notna(frame.values) might\r\n",
      "            # upcast everything to object\r\n",
      "            mask = notna(frame).values\r\n",
      "        else:\r\n",
      "            # But use the speedup when we have homogeneous dtypes\r\n",
      "            mask = notna(frame.values)\r\n",
      "\r\n",
      "        if axis == 1:\r\n",
      "            # We're transposing the mask rather than frame to avoid potential\r\n",
      "            # upcasts to object, which induces a ~20x slowdown\r\n",
      "            mask = mask.T\r\n",
      "\r\n",
      "        if isinstance(level, compat.string_types):\r\n",
      "            level = count_axis._get_level_number(level)\r\n",
      "\r\n",
      "        level_index = count_axis.levels[level]\r\n",
      "        labels = _ensure_int64(count_axis.labels[level])\r\n",
      "        counts = lib.count_level_2d(mask, labels, len(level_index), axis=0)\r\n",
      "\r\n",
      "        result = DataFrame(counts, index=level_index, columns=agg_axis)\r\n",
      "\r\n",
      "        if axis == 1:\r\n",
      "            # Undo our earlier transpose\r\n",
      "            return result.T\r\n",
      "        else:\r\n",
      "            return result\r\n",
      "\r\n",
      "    def _reduce(self, op, name, axis=0, skipna=True, numeric_only=None,\r\n",
      "                filter_type=None, **kwds):\r\n",
      "        axis = self._get_axis_number(axis)\r\n",
      "\r\n",
      "        def f(x):\r\n",
      "            return op(x, axis=axis, skipna=skipna, **kwds)\r\n",
      "\r\n",
      "        labels = self._get_agg_axis(axis)\r\n",
      "\r\n",
      "        # exclude timedelta/datetime unless we are uniform types\r\n",
      "        if axis == 1 and self._is_mixed_type and self._is_datelike_mixed_type:\r\n",
      "            numeric_only = True\r\n",
      "\r\n",
      "        if numeric_only is None:\r\n",
      "            try:\r\n",
      "                values = self.values\r\n",
      "                result = f(values)\r\n",
      "            except Exception as e:\r\n",
      "\r\n",
      "                # try by-column first\r\n",
      "                if filter_type is None and axis == 0:\r\n",
      "                    try:\r\n",
      "\r\n",
      "                        # this can end up with a non-reduction\r\n",
      "                        # but not always. if the types are mixed\r\n",
      "                        # with datelike then need to make sure a series\r\n",
      "\r\n",
      "                        # we only end up here if we have not specified\r\n",
      "                        # numeric_only and yet we have tried a\r\n",
      "                        # column-by-column reduction, where we have mixed type.\r\n",
      "                        # So let's just do what we can\r\n",
      "                        result = self.apply(f, reduce=False,\r\n",
      "                                            ignore_failures=True)\r\n",
      "                        if result.ndim == self.ndim:\r\n",
      "                            result = result.iloc[0]\r\n",
      "                        return result\r\n",
      "                    except:\r\n",
      "                        pass\r\n",
      "\r\n",
      "                if filter_type is None or filter_type == 'numeric':\r\n",
      "                    data = self._get_numeric_data()\r\n",
      "                elif filter_type == 'bool':\r\n",
      "                    data = self._get_bool_data()\r\n",
      "                else:  # pragma: no cover\r\n",
      "                    e = NotImplementedError(\"Handling exception with filter_\"\r\n",
      "                                            \"type %s not implemented.\" %\r\n",
      "                                            filter_type)\r\n",
      "                    raise_with_traceback(e)\r\n",
      "                with np.errstate(all='ignore'):\r\n",
      "                    result = f(data.values)\r\n",
      "                labels = data._get_agg_axis(axis)\r\n",
      "        else:\r\n",
      "            if numeric_only:\r\n",
      "                if filter_type is None or filter_type == 'numeric':\r\n",
      "                    data = self._get_numeric_data()\r\n",
      "                elif filter_type == 'bool':\r\n",
      "                    data = self._get_bool_data()\r\n",
      "                else:  # pragma: no cover\r\n",
      "                    msg = (\"Generating numeric_only data with filter_type %s\"\r\n",
      "                           \"not supported.\" % filter_type)\r\n",
      "                    raise NotImplementedError(msg)\r\n",
      "                values = data.values\r\n",
      "                labels = data._get_agg_axis(axis)\r\n",
      "            else:\r\n",
      "                values = self.values\r\n",
      "            result = f(values)\r\n",
      "\r\n",
      "        if hasattr(result, 'dtype') and is_object_dtype(result.dtype):\r\n",
      "            try:\r\n",
      "                if filter_type is None or filter_type == 'numeric':\r\n",
      "                    result = result.astype(np.float64)\r\n",
      "                elif filter_type == 'bool' and notna(result).all():\r\n",
      "                    result = result.astype(np.bool_)\r\n",
      "            except (ValueError, TypeError):\r\n",
      "\r\n",
      "                # try to coerce to the original dtypes item by item if we can\r\n",
      "                if axis == 0:\r\n",
      "                    result = coerce_to_dtypes(result, self.dtypes)\r\n",
      "\r\n",
      "        return Series(result, index=labels)\r\n",
      "\r\n",
      "    def nunique(self, axis=0, dropna=True):\r\n",
      "        \"\"\"\r\n",
      "        Return Series with number of distinct observations over requested\r\n",
      "        axis.\r\n",
      "\r\n",
      "        .. versionadded:: 0.20.0\r\n",
      "\r\n",
      "        Parameters\r\n",
      "        ----------\r\n",
      "        axis : {0 or 'index', 1 or 'columns'}, default 0\r\n",
      "        dropna : boolean, default True\r\n",
      "            Don't include NaN in the counts.\r\n",
      "\r\n",
      "        Returns\r\n",
      "        -------\r\n",
      "        nunique : Series\r\n",
      "\r\n",
      "        Examples\r\n",
      "        --------\r\n",
      "        >>> df = pd.DataFrame({'A': [1, 2, 3], 'B': [1, 1, 1]})\r\n",
      "        >>> df.nunique()\r\n",
      "        A    3\r\n",
      "        B    1\r\n",
      "\r\n",
      "        >>> df.nunique(axis=1)\r\n",
      "        0    1\r\n",
      "        1    2\r\n",
      "        2    2\r\n",
      "        \"\"\"\r\n",
      "        return self.apply(Series.nunique, axis=axis, dropna=dropna)\r\n",
      "\r\n",
      "    def idxmin(self, axis=0, skipna=True):\r\n",
      "        \"\"\"\r\n",
      "        Return index of first occurrence of minimum over requested axis.\r\n",
      "        NA/null values are excluded.\r\n",
      "\r\n",
      "        Parameters\r\n",
      "        ----------\r\n",
      "        axis : {0 or 'index', 1 or 'columns'}, default 0\r\n",
      "            0 or 'index' for row-wise, 1 or 'columns' for column-wise\r\n",
      "        skipna : boolean, default True\r\n",
      "            Exclude NA/null values. If an entire row/column is NA, the result\r\n",
      "            will be NA.\r\n",
      "\r\n",
      "        Raises\r\n",
      "        ------\r\n",
      "        ValueError\r\n",
      "            * If the row/column is empty\r\n",
      "\r\n",
      "        Returns\r\n",
      "        -------\r\n",
      "        idxmin : Series\r\n",
      "\r\n",
      "        Notes\r\n",
      "        -----\r\n",
      "        This method is the DataFrame version of ``ndarray.argmin``.\r\n",
      "\r\n",
      "        See Also\r\n",
      "        --------\r\n",
      "        Series.idxmin\r\n",
      "        \"\"\"\r\n",
      "        axis = self._get_axis_number(axis)\r\n",
      "        indices = nanops.nanargmin(self.values, axis=axis, skipna=skipna)\r\n",
      "        index = self._get_axis(axis)\r\n",
      "        result = [index[i] if i >= 0 else np.nan for i in indices]\r\n",
      "        return Series(result, index=self._get_agg_axis(axis))\r\n",
      "\r\n",
      "    def idxmax(self, axis=0, skipna=True):\r\n",
      "        \"\"\"\r\n",
      "        Return index of first occurrence of maximum over requested axis.\r\n",
      "        NA/null values are excluded.\r\n",
      "\r\n",
      "        Parameters\r\n",
      "        ----------\r\n",
      "        axis : {0 or 'index', 1 or 'columns'}, default 0\r\n",
      "            0 or 'index' for row-wise, 1 or 'columns' for column-wise\r\n",
      "        skipna : boolean, default True\r\n",
      "            Exclude NA/null values. If an entire row/column is NA, the result\r\n",
      "            will be NA.\r\n",
      "\r\n",
      "        Raises\r\n",
      "        ------\r\n",
      "        ValueError\r\n",
      "            * If the row/column is empty\r\n",
      "\r\n",
      "        Returns\r\n",
      "        -------\r\n",
      "        idxmax : Series\r\n",
      "\r\n",
      "        Notes\r\n",
      "        -----\r\n",
      "        This method is the DataFrame version of ``ndarray.argmax``.\r\n",
      "\r\n",
      "        See Also\r\n",
      "        --------\r\n",
      "        Series.idxmax\r\n",
      "        \"\"\"\r\n",
      "        axis = self._get_axis_number(axis)\r\n",
      "        indices = nanops.nanargmax(self.values, axis=axis, skipna=skipna)\r\n",
      "        index = self._get_axis(axis)\r\n",
      "        result = [index[i] if i >= 0 else np.nan for i in indices]\r\n",
      "        return Series(result, index=self._get_agg_axis(axis))\r\n",
      "\r\n",
      "    def _get_agg_axis(self, axis_num):\r\n",
      "        \"\"\" let's be explict about this \"\"\"\r\n",
      "        if axis_num == 0:\r\n",
      "            return self.columns\r\n",
      "        elif axis_num == 1:\r\n",
      "            return self.index\r\n",
      "        else:\r\n",
      "            raise ValueError('Axis must be 0 or 1 (got %r)' % axis_num)\r\n",
      "\r\n",
      "    def mode(self, axis=0, numeric_only=False):\r\n",
      "        \"\"\"\r\n",
      "        Gets the mode(s) of each element along the axis selected. Adds a row\r\n",
      "        for each mode per label, fills in gaps with nan.\r\n",
      "\r\n",
      "        Note that there could be multiple values returned for the selected\r\n",
      "        axis (when more than one item share the maximum frequency), which is\r\n",
      "        the reason why a dataframe is returned. If you want to impute missing\r\n",
      "        values with the mode in a dataframe ``df``, you can just do this:\r\n",
      "        ``df.fillna(df.mode().iloc[0])``\r\n",
      "\r\n",
      "        Parameters\r\n",
      "        ----------\r\n",
      "        axis : {0 or 'index', 1 or 'columns'}, default 0\r\n",
      "            * 0 or 'index' : get mode of each column\r\n",
      "            * 1 or 'columns' : get mode of each row\r\n",
      "        numeric_only : boolean, default False\r\n",
      "            if True, only apply to numeric columns\r\n",
      "\r\n",
      "        Returns\r\n",
      "        -------\r\n",
      "        modes : DataFrame (sorted)\r\n",
      "\r\n",
      "        Examples\r\n",
      "        --------\r\n",
      "        >>> df = pd.DataFrame({'A': [1, 2, 1, 2, 1, 2, 3]})\r\n",
      "        >>> df.mode()\r\n",
      "           A\r\n",
      "        0  1\r\n",
      "        1  2\r\n",
      "        \"\"\"\r\n",
      "        data = self if not numeric_only else self._get_numeric_data()\r\n",
      "\r\n",
      "        def f(s):\r\n",
      "            return s.mode()\r\n",
      "\r\n",
      "        return data.apply(f, axis=axis)\r\n",
      "\r\n",
      "    def quantile(self, q=0.5, axis=0, numeric_only=True,\r\n",
      "                 interpolation='linear'):\r\n",
      "        \"\"\"\r\n",
      "        Return values at the given quantile over requested axis, a la\r\n",
      "        numpy.percentile.\r\n",
      "\r\n",
      "        Parameters\r\n",
      "        ----------\r\n",
      "        q : float or array-like, default 0.5 (50% quantile)\r\n",
      "            0 <= q <= 1, the quantile(s) to compute\r\n",
      "        axis : {0, 1, 'index', 'columns'} (default 0)\r\n",
      "            0 or 'index' for row-wise, 1 or 'columns' for column-wise\r\n",
      "        interpolation : {'linear', 'lower', 'higher', 'midpoint', 'nearest'}\r\n",
      "            .. versionadded:: 0.18.0\r\n",
      "\r\n",
      "            This optional parameter specifies the interpolation method to use,\r\n",
      "            when the desired quantile lies between two data points `i` and `j`:\r\n",
      "\r\n",
      "            * linear: `i + (j - i) * fraction`, where `fraction` is the\r\n",
      "              fractional part of the index surrounded by `i` and `j`.\r\n",
      "            * lower: `i`.\r\n",
      "            * higher: `j`.\r\n",
      "            * nearest: `i` or `j` whichever is nearest.\r\n",
      "            * midpoint: (`i` + `j`) / 2.\r\n",
      "\r\n",
      "        Returns\r\n",
      "        -------\r\n",
      "        quantiles : Series or DataFrame\r\n",
      "\r\n",
      "            - If ``q`` is an array, a DataFrame will be returned where the\r\n",
      "              index is ``q``, the columns are the columns of self, and the\r\n",
      "              values are the quantiles.\r\n",
      "            - If ``q`` is a float, a Series will be returned where the\r\n",
      "              index is the columns of self and the values are the quantiles.\r\n",
      "\r\n",
      "        Examples\r\n",
      "        --------\r\n",
      "\r\n",
      "        >>> df = DataFrame(np.array([[1, 1], [2, 10], [3, 100], [4, 100]]),\r\n",
      "                           columns=['a', 'b'])\r\n",
      "        >>> df.quantile(.1)\r\n",
      "        a    1.3\r\n",
      "        b    3.7\r\n",
      "        dtype: float64\r\n",
      "        >>> df.quantile([.1, .5])\r\n",
      "               a     b\r\n",
      "        0.1  1.3   3.7\r\n",
      "        0.5  2.5  55.0\r\n",
      "        \"\"\"\r\n",
      "        self._check_percentile(q)\r\n",
      "\r\n",
      "        data = self._get_numeric_data() if numeric_only else self\r\n",
      "        axis = self._get_axis_number(axis)\r\n",
      "        is_transposed = axis == 1\r\n",
      "\r\n",
      "        if is_transposed:\r\n",
      "            data = data.T\r\n",
      "\r\n",
      "        result = data._data.quantile(qs=q,\r\n",
      "                                     axis=1,\r\n",
      "                                     interpolation=interpolation,\r\n",
      "                                     transposed=is_transposed)\r\n",
      "\r\n",
      "        if result.ndim == 2:\r\n",
      "            result = self._constructor(result)\r\n",
      "        else:\r\n",
      "            result = self._constructor_sliced(result, name=q)\r\n",
      "\r\n",
      "        if is_transposed:\r\n",
      "            result = result.T\r\n",
      "\r\n",
      "        return result\r\n",
      "\r\n",
      "    def to_timestamp(self, freq=None, how='start', axis=0, copy=True):\r\n",
      "        \"\"\"\r\n",
      "        Cast to DatetimeIndex of timestamps, at *beginning* of period\r\n",
      "\r\n",
      "        Parameters\r\n",
      "        ----------\r\n",
      "        freq : string, default frequency of PeriodIndex\r\n",
      "            Desired frequency\r\n",
      "        how : {'s', 'e', 'start', 'end'}\r\n",
      "            Convention for converting period to timestamp; start of period\r\n",
      "            vs. end\r\n",
      "        axis : {0 or 'index', 1 or 'columns'}, default 0\r\n",
      "            The axis to convert (the index by default)\r\n",
      "        copy : boolean, default True\r\n",
      "            If false then underlying input data is not copied\r\n",
      "\r\n",
      "        Returns\r\n",
      "        -------\r\n",
      "        df : DataFrame with DatetimeIndex\r\n",
      "        \"\"\"\r\n",
      "        new_data = self._data\r\n",
      "        if copy:\r\n",
      "            new_data = new_data.copy()\r\n",
      "\r\n",
      "        axis = self._get_axis_number(axis)\r\n",
      "        if axis == 0:\r\n",
      "            new_data.set_axis(1, self.index.to_timestamp(freq=freq, how=how))\r\n",
      "        elif axis == 1:\r\n",
      "            new_data.set_axis(0, self.columns.to_timestamp(freq=freq, how=how))\r\n",
      "        else:  # pragma: no cover\r\n",
      "            raise AssertionError('Axis must be 0 or 1. Got %s' % str(axis))\r\n",
      "\r\n",
      "        return self._constructor(new_data)\r\n",
      "\r\n",
      "    def to_period(self, freq=None, axis=0, copy=True):\r\n",
      "        \"\"\"\r\n",
      "        Convert DataFrame from DatetimeIndex to PeriodIndex with desired\r\n",
      "        frequency (inferred from index if not passed)\r\n",
      "\r\n",
      "        Parameters\r\n",
      "        ----------\r\n",
      "        freq : string, default\r\n",
      "        axis : {0 or 'index', 1 or 'columns'}, default 0\r\n",
      "            The axis to convert (the index by default)\r\n",
      "        copy : boolean, default True\r\n",
      "            If False then underlying input data is not copied\r\n",
      "\r\n",
      "        Returns\r\n",
      "        -------\r\n",
      "        ts : TimeSeries with PeriodIndex\r\n",
      "        \"\"\"\r\n",
      "        new_data = self._data\r\n",
      "        if copy:\r\n",
      "            new_data = new_data.copy()\r\n",
      "\r\n",
      "        axis = self._get_axis_number(axis)\r\n",
      "        if axis == 0:\r\n",
      "            new_data.set_axis(1, self.index.to_period(freq=freq))\r\n",
      "        elif axis == 1:\r\n",
      "            new_data.set_axis(0, self.columns.to_period(freq=freq))\r\n",
      "        else:  # pragma: no cover\r\n",
      "            raise AssertionError('Axis must be 0 or 1. Got %s' % str(axis))\r\n",
      "\r\n",
      "        return self._constructor(new_data)\r\n",
      "\r\n",
      "    def isin(self, values):\r\n",
      "        \"\"\"\r\n",
      "        Return boolean DataFrame showing whether each element in the\r\n",
      "        DataFrame is contained in values.\r\n",
      "\r\n",
      "        Parameters\r\n",
      "        ----------\r\n",
      "        values : iterable, Series, DataFrame or dictionary\r\n",
      "            The result will only be true at a location if all the\r\n",
      "            labels match. If `values` is a Series, that's the index. If\r\n",
      "            `values` is a dictionary, the keys must be the column names,\r\n",
      "            which must match. If `values` is a DataFrame,\r\n",
      "            then both the index and column labels must match.\r\n",
      "\r\n",
      "        Returns\r\n",
      "        -------\r\n",
      "\r\n",
      "        DataFrame of booleans\r\n",
      "\r\n",
      "        Examples\r\n",
      "        --------\r\n",
      "        When ``values`` is a list:\r\n",
      "\r\n",
      "        >>> df = DataFrame({'A': [1, 2, 3], 'B': ['a', 'b', 'f']})\r\n",
      "        >>> df.isin([1, 3, 12, 'a'])\r\n",
      "               A      B\r\n",
      "        0   True   True\r\n",
      "        1  False  False\r\n",
      "        2   True  False\r\n",
      "\r\n",
      "        When ``values`` is a dict:\r\n",
      "\r\n",
      "        >>> df = DataFrame({'A': [1, 2, 3], 'B': [1, 4, 7]})\r\n",
      "        >>> df.isin({'A': [1, 3], 'B': [4, 7, 12]})\r\n",
      "               A      B\r\n",
      "        0   True  False  # Note that B didn't match the 1 here.\r\n",
      "        1  False   True\r\n",
      "        2   True   True\r\n",
      "\r\n",
      "        When ``values`` is a Series or DataFrame:\r\n",
      "\r\n",
      "        >>> df = DataFrame({'A': [1, 2, 3], 'B': ['a', 'b', 'f']})\r\n",
      "        >>> other = DataFrame({'A': [1, 3, 3, 2], 'B': ['e', 'f', 'f', 'e']})\r\n",
      "        >>> df.isin(other)\r\n",
      "               A      B\r\n",
      "        0   True  False\r\n",
      "        1  False  False  # Column A in `other` has a 3, but not at index 1.\r\n",
      "        2   True   True\r\n",
      "        \"\"\"\r\n",
      "        if isinstance(values, dict):\r\n",
      "            from pandas.core.reshape.concat import concat\r\n",
      "            values = collections.defaultdict(list, values)\r\n",
      "            return concat((self.iloc[:, [i]].isin(values[col])\r\n",
      "                           for i, col in enumerate(self.columns)), axis=1)\r\n",
      "        elif isinstance(values, Series):\r\n",
      "            if not values.index.is_unique:\r\n",
      "                raise ValueError(\"cannot compute isin with \"\r\n",
      "                                 \"a duplicate axis.\")\r\n",
      "            return self.eq(values.reindex_like(self), axis='index')\r\n",
      "        elif isinstance(values, DataFrame):\r\n",
      "            if not (values.columns.is_unique and values.index.is_unique):\r\n",
      "                raise ValueError(\"cannot compute isin with \"\r\n",
      "                                 \"a duplicate axis.\")\r\n",
      "            return self.eq(values.reindex_like(self))\r\n",
      "        else:\r\n",
      "            if not is_list_like(values):\r\n",
      "                raise TypeError(\"only list-like or dict-like objects are \"\r\n",
      "                                \"allowed to be passed to DataFrame.isin(), \"\r\n",
      "                                \"you passed a \"\r\n",
      "                                \"{0!r}\".format(type(values).__name__))\r\n",
      "            return DataFrame(\r\n",
      "                algorithms.isin(self.values.ravel(),\r\n",
      "                                values).reshape(self.shape), self.index,\r\n",
      "                self.columns)\r\n",
      "\r\n",
      "    # ----------------------------------------------------------------------\r\n",
      "    # Add plotting methods to DataFrame\r\n",
      "    plot = accessor.AccessorProperty(gfx.FramePlotMethods,\r\n",
      "                                     gfx.FramePlotMethods)\r\n",
      "    hist = gfx.hist_frame\r\n",
      "    boxplot = gfx.boxplot_frame\r\n",
      "\r\n",
      "\r\n",
      "DataFrame._setup_axes(['index', 'columns'], info_axis=1, stat_axis=0,\r\n",
      "                      axes_are_reversed=True, aliases={'rows': 0})\r\n",
      "DataFrame._add_numeric_operations()\r\n",
      "DataFrame._add_series_or_dataframe_operations()\r\n",
      "\r\n",
      "ops.add_flex_arithmetic_methods(DataFrame, **ops.frame_flex_funcs)\r\n",
      "ops.add_special_arithmetic_methods(DataFrame, **ops.frame_special_funcs)\r\n",
      "\r\n",
      "_EMPTY_SERIES = Series([])\r\n",
      "\r\n",
      "\r\n",
      "def _arrays_to_mgr(arrays, arr_names, index, columns, dtype=None):\r\n",
      "    \"\"\"\r\n",
      "    Segregate Series based on type and coerce into matrices.\r\n",
      "    Needs to handle a lot of exceptional cases.\r\n",
      "    \"\"\"\r\n",
      "    # figure out the index, if necessary\r\n",
      "    if index is None:\r\n",
      "        index = extract_index(arrays)\r\n",
      "    else:\r\n",
      "        index = _ensure_index(index)\r\n",
      "\r\n",
      "    # don't force copy because getting jammed in an ndarray anyway\r\n",
      "    arrays = _homogenize(arrays, index, dtype)\r\n",
      "\r\n",
      "    # from BlockManager perspective\r\n",
      "    axes = [_ensure_index(columns), _ensure_index(index)]\r\n",
      "\r\n",
      "    return create_block_manager_from_arrays(arrays, arr_names, axes)\r\n",
      "\r\n",
      "\r\n",
      "def extract_index(data):\r\n",
      "    from pandas.core.index import _union_indexes\r\n",
      "\r\n",
      "    index = None\r\n",
      "    if len(data) == 0:\r\n",
      "        index = Index([])\r\n",
      "    elif len(data) > 0:\r\n",
      "        raw_lengths = []\r\n",
      "        indexes = []\r\n",
      "\r\n",
      "        have_raw_arrays = False\r\n",
      "        have_series = False\r\n",
      "        have_dicts = False\r\n",
      "\r\n",
      "        for v in data:\r\n",
      "            if isinstance(v, Series):\r\n",
      "                have_series = True\r\n",
      "                indexes.append(v.index)\r\n",
      "            elif isinstance(v, dict):\r\n",
      "                have_dicts = True\r\n",
      "                indexes.append(list(v.keys()))\r\n",
      "            elif is_list_like(v) and getattr(v, 'ndim', 1) == 1:\r\n",
      "                have_raw_arrays = True\r\n",
      "                raw_lengths.append(len(v))\r\n",
      "\r\n",
      "        if not indexes and not raw_lengths:\r\n",
      "            raise ValueError('If using all scalar values, you must pass'\r\n",
      "                             ' an index')\r\n",
      "\r\n",
      "        if have_series or have_dicts:\r\n",
      "            index = _union_indexes(indexes)\r\n",
      "\r\n",
      "        if have_raw_arrays:\r\n",
      "            lengths = list(set(raw_lengths))\r\n",
      "            if len(lengths) > 1:\r\n",
      "                raise ValueError('arrays must all be same length')\r\n",
      "\r\n",
      "            if have_dicts:\r\n",
      "                raise ValueError('Mixing dicts with non-Series may lead to '\r\n",
      "                                 'ambiguous ordering.')\r\n",
      "\r\n",
      "            if have_series:\r\n",
      "                if lengths[0] != len(index):\r\n",
      "                    msg = ('array length %d does not match index length %d' %\r\n",
      "                           (lengths[0], len(index)))\r\n",
      "                    raise ValueError(msg)\r\n",
      "            else:\r\n",
      "                index = _default_index(lengths[0])\r\n",
      "\r\n",
      "    return _ensure_index(index)\r\n",
      "\r\n",
      "\r\n",
      "def _prep_ndarray(values, copy=True):\r\n",
      "    if not isinstance(values, (np.ndarray, Series, Index)):\r\n",
      "        if len(values) == 0:\r\n",
      "            return np.empty((0, 0), dtype=object)\r\n",
      "\r\n",
      "        def convert(v):\r\n",
      "            return maybe_convert_platform(v)\r\n",
      "\r\n",
      "        # we could have a 1-dim or 2-dim list here\r\n",
      "        # this is equiv of np.asarray, but does object conversion\r\n",
      "        # and platform dtype preservation\r\n",
      "        try:\r\n",
      "            if is_list_like(values[0]) or hasattr(values[0], 'len'):\r\n",
      "                values = np.array([convert(v) for v in values])\r\n",
      "            else:\r\n",
      "                values = convert(values)\r\n",
      "        except:\r\n",
      "            values = convert(values)\r\n",
      "\r\n",
      "    else:\r\n",
      "\r\n",
      "        # drop subclass info, do not copy data\r\n",
      "        values = np.asarray(values)\r\n",
      "        if copy:\r\n",
      "            values = values.copy()\r\n",
      "\r\n",
      "    if values.ndim == 1:\r\n",
      "        values = values.reshape((values.shape[0], 1))\r\n",
      "    elif values.ndim != 2:\r\n",
      "        raise ValueError('Must pass 2-d input')\r\n",
      "\r\n",
      "    return values\r",
      "\r\n",
      "\r\n",
      "\r\n",
      "def _to_arrays(data, columns, coerce_float=False, dtype=None):\r\n",
      "    \"\"\"\r\n",
      "    Return list of arrays, columns\r\n",
      "    \"\"\"\r\n",
      "    if isinstance(data, DataFrame):\r\n",
      "        if columns is not None:\r\n",
      "            arrays = [data._ixs(i, axis=1).values\r\n",
      "                      for i, col in enumerate(data.columns) if col in columns]\r\n",
      "        else:\r\n",
      "            columns = data.columns\r\n",
      "            arrays = [data._ixs(i, axis=1).values for i in range(len(columns))]\r\n",
      "\r\n",
      "        return arrays, columns\r\n",
      "\r\n",
      "    if not len(data):\r\n",
      "        if isinstance(data, np.ndarray):\r\n",
      "            columns = data.dtype.names\r\n",
      "            if columns is not None:\r\n",
      "                return [[]] * len(columns), columns\r\n",
      "        return [], []  # columns if columns is not None else []\r\n",
      "    if isinstance(data[0], (list, tuple)):\r\n",
      "        return _list_to_arrays(data, columns, coerce_float=coerce_float,\r\n",
      "                               dtype=dtype)\r\n",
      "    elif isinstance(data[0], collections.Mapping):\r\n",
      "        return _list_of_dict_to_arrays(data, columns,\r\n",
      "                                       coerce_float=coerce_float, dtype=dtype)\r\n",
      "    elif isinstance(data[0], Series):\r\n",
      "        return _list_of_series_to_arrays(data, columns,\r\n",
      "                                         coerce_float=coerce_float,\r\n",
      "                                         dtype=dtype)\r\n",
      "    elif isinstance(data[0], Categorical):\r\n",
      "        if columns is None:\r\n",
      "            columns = _default_index(len(data))\r\n",
      "        return data, columns\r\n",
      "    elif (isinstance(data, (np.ndarray, Series, Index)) and\r\n",
      "          data.dtype.names is not None):\r\n",
      "\r\n",
      "        columns = list(data.dtype.names)\r\n",
      "        arrays = [data[k] for k in columns]\r\n",
      "        return arrays, columns\r\n",
      "    else:\r\n",
      "        # last ditch effort\r\n",
      "        data = lmap(tuple, data)\r\n",
      "        return _list_to_arrays(data, columns, coerce_float=coerce_float,\r\n",
      "                               dtype=dtype)\r\n",
      "\r\n",
      "\r\n",
      "def _masked_rec_array_to_mgr(data, index, columns, dtype, copy):\r\n",
      "    \"\"\" extract from a masked rec array and create the manager \"\"\"\r\n",
      "\r\n",
      "    # essentially process a record array then fill it\r\n",
      "    fill_value = data.fill_value\r\n",
      "    fdata = ma.getdata(data)\r\n",
      "    if index is None:\r\n",
      "        index = _get_names_from_index(fdata)\r\n",
      "        if index is None:\r\n",
      "            index = _default_index(len(data))\r\n",
      "    index = _ensure_index(index)\r\n",
      "\r\n",
      "    if columns is not None:\r\n",
      "        columns = _ensure_index(columns)\r\n",
      "    arrays, arr_columns = _to_arrays(fdata, columns)\r\n",
      "\r\n",
      "    # fill if needed\r\n",
      "    new_arrays = []\r\n",
      "    for fv, arr, col in zip(fill_value, arrays, arr_columns):\r\n",
      "        mask = ma.getmaskarray(data[col])\r\n",
      "        if mask.any():\r\n",
      "            arr, fv = maybe_upcast(arr, fill_value=fv, copy=True)\r\n",
      "            arr[mask] = fv\r\n",
      "        new_arrays.append(arr)\r\n",
      "\r\n",
      "    # create the manager\r\n",
      "    arrays, arr_columns = _reorder_arrays(new_arrays, arr_columns, columns)\r\n",
      "    if columns is None:\r\n",
      "        columns = arr_columns\r\n",
      "\r\n",
      "    mgr = _arrays_to_mgr(arrays, arr_columns, index, columns)\r\n",
      "\r\n",
      "    if copy:\r\n",
      "        mgr = mgr.copy()\r\n",
      "    return mgr\r\n",
      "\r\n",
      "\r\n",
      "def _reorder_arrays(arrays, arr_columns, columns):\r\n",
      "    # reorder according to the columns\r\n",
      "    if (columns is not None and len(columns) and arr_columns is not None and\r\n",
      "            len(arr_columns)):\r\n",
      "        indexer = _ensure_index(arr_columns).get_indexer(columns)\r\n",
      "        arr_columns = _ensure_index([arr_columns[i] for i in indexer])\r\n",
      "        arrays = [arrays[i] for i in indexer]\r\n",
      "    return arrays, arr_columns\r\n",
      "\r\n",
      "\r\n",
      "def _list_to_arrays(data, columns, coerce_float=False, dtype=None):\r\n",
      "    if len(data) > 0 and isinstance(data[0], tuple):\r\n",
      "        content = list(lib.to_object_array_tuples(data).T)\r\n",
      "    else:\r\n",
      "        # list of lists\r\n",
      "        content = list(lib.to_object_array(data).T)\r\n",
      "    return _convert_object_array(content, columns, dtype=dtype,\r\n",
      "                                 coerce_float=coerce_float)\r\n",
      "\r\n",
      "\r\n",
      "def _list_of_series_to_arrays(data, columns, coerce_float=False, dtype=None):\r\n",
      "    from pandas.core.index import _get_objs_combined_axis\r\n",
      "\r\n",
      "    if columns is None:\r\n",
      "        columns = _get_objs_combined_axis(data)\r\n",
      "\r\n",
      "    indexer_cache = {}\r\n",
      "\r\n",
      "    aligned_values = []\r\n",
      "    for s in data:\r\n",
      "        index = getattr(s, 'index', None)\r\n",
      "        if index is None:\r\n",
      "            index = _default_index(len(s))\r\n",
      "\r\n",
      "        if id(index) in indexer_cache:\r\n",
      "            indexer = indexer_cache[id(index)]\r\n",
      "        else:\r\n",
      "            indexer = indexer_cache[id(index)] = index.get_indexer(columns)\r\n",
      "\r\n",
      "        values = _values_from_object(s)\r\n",
      "        aligned_values.append(algorithms.take_1d(values, indexer))\r\n",
      "\r\n",
      "    values = np.vstack(aligned_values)\r\n",
      "\r\n",
      "    if values.dtype == np.object_:\r\n",
      "        content = list(values.T)\r\n",
      "        return _convert_object_array(content, columns, dtype=dtype,\r\n",
      "                                     coerce_float=coerce_float)\r\n",
      "    else:\r\n",
      "        return values.T, columns\r\n",
      "\r\n",
      "\r\n",
      "def _list_of_dict_to_arrays(data, columns, coerce_float=False, dtype=None):\r\n",
      "    if columns is None:\r\n",
      "        gen = (list(x.keys()) for x in data)\r\n",
      "        sort = not any(isinstance(d, OrderedDict) for d in data)\r\n",
      "        columns = lib.fast_unique_multiple_list_gen(gen, sort=sort)\r\n",
      "\r\n",
      "    # assure that they are of the base dict class and not of derived\r\n",
      "    # classes\r\n",
      "    data = [(type(d) is dict) and d or dict(d) for d in data]\r\n",
      "\r\n",
      "    content = list(lib.dicts_to_array(data, list(columns)).T)\r\n",
      "    return _convert_object_array(content, columns, dtype=dtype,\r\n",
      "                                 coerce_float=coerce_float)\r\n",
      "\r\n",
      "\r\n",
      "def _convert_object_array(content, columns, coerce_float=False, dtype=None):\r\n",
      "    if columns is None:\r\n",
      "        columns = _default_index(len(content))\r\n",
      "    else:\r\n",
      "        if len(columns) != len(content):  # pragma: no cover\r\n",
      "            # caller's responsibility to check for this...\r\n",
      "            raise AssertionError('%d columns passed, passed data had %s '\r\n",
      "                                 'columns' % (len(columns), len(content)))\r\n",
      "\r\n",
      "    # provide soft conversion of object dtypes\r\n",
      "    def convert(arr):\r\n",
      "        if dtype != object and dtype != np.object:\r\n",
      "            arr = lib.maybe_convert_objects(arr, try_float=coerce_float)\r\n",
      "            arr = maybe_cast_to_datetime(arr, dtype)\r\n",
      "        return arr\r\n",
      "\r\n",
      "    arrays = [convert(arr) for arr in content]\r\n",
      "\r\n",
      "    return arrays, columns\r\n",
      "\r\n",
      "\r\n",
      "def _get_names_from_index(data):\r\n",
      "    has_some_name = any([getattr(s, 'name', None) is not None for s in data])\r\n",
      "    if not has_some_name:\r\n",
      "        return _default_index(len(data))\r\n",
      "\r\n",
      "    index = lrange(len(data))\r\n",
      "    count = 0\r\n",
      "    for i, s in enumerate(data):\r\n",
      "        n = getattr(s, 'name', None)\r\n",
      "        if n is not None:\r\n",
      "            index[i] = n\r\n",
      "        else:\r\n",
      "            index[i] = 'Unnamed %d' % count\r\n",
      "            count += 1\r\n",
      "\r\n",
      "    return index\r\n",
      "\r\n",
      "\r\n",
      "def _homogenize(data, index, dtype=None):\r\n",
      "    from pandas.core.series import _sanitize_array\r\n",
      "\r\n",
      "    oindex = None\r\n",
      "    homogenized = []\r\n",
      "\r\n",
      "    for v in data:\r\n",
      "        if isinstance(v, Series):\r\n",
      "            if dtype is not None:\r\n",
      "                v = v.astype(dtype)\r\n",
      "            if v.index is not index:\r\n",
      "                # Forces alignment. No need to copy data since we\r\n",
      "                # are putting it into an ndarray later\r\n",
      "                v = v.reindex(index, copy=False)\r\n",
      "        else:\r\n",
      "            if isinstance(v, dict):\r\n",
      "                if oindex is None:\r\n",
      "                    oindex = index.astype('O')\r\n",
      "\r\n",
      "                if isinstance(index, (DatetimeIndex, TimedeltaIndex)):\r\n",
      "                    v = _dict_compat(v)\r\n",
      "                else:\r\n",
      "                    v = dict(v)\r\n",
      "                v = lib.fast_multiget(v, oindex.values, default=np.nan)\r\n",
      "            v = _sanitize_array(v, index, dtype=dtype, copy=False,\r\n",
      "                                raise_cast_failure=False)\r\n",
      "\r\n",
      "        homogenized.append(v)\r\n",
      "\r\n",
      "    return homogenized\r\n",
      "\r\n",
      "\r\n",
      "def _from_nested_dict(data):\r\n",
      "    # TODO: this should be seriously cythonized\r\n",
      "    new_data = OrderedDict()\r\n",
      "    for index, s in compat.iteritems(data):\r\n",
      "        for col, v in compat.iteritems(s):\r\n",
      "            new_data[col] = new_data.get(col, OrderedDict())\r\n",
      "            new_data[col][index] = v\r\n",
      "    return new_data\r\n",
      "\r\n",
      "\r\n",
      "def _put_str(s, space):\r\n",
      "    return ('%s' % s)[:space].ljust(space)\r\n"
     ]
    }
   ],
   "source": [
    "!cat ~/anaconda3/lib/python3.6/site-packages/pandas/core/frame.py"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 62,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.axes._subplots.AxesSubplot at 0x11e89a0f0>"
      ]
     },
     "execution_count": 62,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "temp_df.unstack().plot.barh()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.axes._subplots.AxesSubplot at 0x112fc3e10>"
      ]
     },
     "execution_count": 55,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "temp_df.plot.barh(sharex = True, sharey = True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "# being a bit too dynamic\r\n",
      "# pylint: disable=E1101\r\n",
      "from __future__ import division\r\n",
      "\r\n",
      "import warnings\r\n",
      "import re\r\n",
      "from collections import namedtuple\r\n",
      "from distutils.version import LooseVersion\r\n",
      "\r\n",
      "import numpy as np\r\n",
      "\r\n",
      "from pandas.util._decorators import cache_readonly\r\n",
      "from pandas.core.base import PandasObject\r\n",
      "from pandas.core.config import get_option\r\n",
      "from pandas.core.dtypes.missing import isna, notna, remove_na_arraylike\r\n",
      "from pandas.core.dtypes.common import (\r\n",
      "    is_list_like,\r\n",
      "    is_integer,\r\n",
      "    is_number,\r\n",
      "    is_hashable,\r\n",
      "    is_iterator)\r\n",
      "from pandas.core.dtypes.generic import ABCSeries\r\n",
      "\r\n",
      "from pandas.core.common import AbstractMethodError, _try_sort, _any_not_none\r\n",
      "from pandas.core.generic import _shared_docs, _shared_doc_kwargs\r\n",
      "from pandas.core.index import Index, MultiIndex\r\n",
      "\r\n",
      "from pandas.core.indexes.period import PeriodIndex\r\n",
      "from pandas.compat import range, lrange, map, zip, string_types\r\n",
      "import pandas.compat as compat\r\n",
      "from pandas.io.formats.printing import pprint_thing\r\n",
      "from pandas.util._decorators import Appender\r\n",
      "\r\n",
      "from pandas.plotting._compat import (_mpl_ge_1_3_1,\r\n",
      "                                     _mpl_ge_1_5_0,\r\n",
      "                                     _mpl_ge_2_0_0)\r\n",
      "from pandas.plotting._style import (plot_params,\r\n",
      "                                    _get_standard_colors)\r\n",
      "from pandas.plotting._tools import (_subplots, _flatten, table,\r\n",
      "                                    _handle_shared_axes, _get_all_lines,\r\n",
      "                                    _get_xlim, _set_ticks_props,\r\n",
      "                                    format_date_labels)\r\n",
      "\r\n",
      "try:\r\n",
      "    from pandas.plotting import _converter\r\n",
      "except ImportError:\r\n",
      "    pass\r\n",
      "else:\r\n",
      "    if get_option('plotting.matplotlib.register_converters'):\r\n",
      "        _converter.register(explicit=True)\r\n",
      "\r\n",
      "\r\n",
      "def _get_standard_kind(kind):\r\n",
      "    return {'density': 'kde'}.get(kind, kind)\r\n",
      "\r\n",
      "\r\n",
      "def _gca(rc=None):\r\n",
      "    import matplotlib.pyplot as plt\r\n",
      "    with plt.rc_context(rc):\r\n",
      "        return plt.gca()\r\n",
      "\r\n",
      "\r\n",
      "def _gcf():\r\n",
      "    import matplotlib.pyplot as plt\r\n",
      "    return plt.gcf()\r\n",
      "\r\n",
      "\r\n",
      "class MPLPlot(object):\r\n",
      "    \"\"\"\r\n",
      "    Base class for assembling a pandas plot using matplotlib\r\n",
      "\r\n",
      "    Parameters\r\n",
      "    ----------\r\n",
      "    data :\r\n",
      "\r\n",
      "    \"\"\"\r\n",
      "\r\n",
      "    @property\r\n",
      "    def _kind(self):\r\n",
      "        \"\"\"Specify kind str. Must be overridden in child class\"\"\"\r\n",
      "        raise NotImplementedError\r\n",
      "\r\n",
      "    _layout_type = 'vertical'\r\n",
      "    _default_rot = 0\r\n",
      "    orientation = None\r\n",
      "    _pop_attributes = ['label', 'style', 'logy', 'logx', 'loglog',\r\n",
      "                       'mark_right', 'stacked']\r\n",
      "    _attr_defaults = {'logy': False, 'logx': False, 'loglog': False,\r\n",
      "                      'mark_right': True, 'stacked': False}\r\n",
      "\r\n",
      "    def __init__(self, data, kind=None, by=None, subplots=False, sharex=None,\r\n",
      "                 sharey=False, use_index=True,\r\n",
      "                 figsize=None, grid=None, legend=True, rot=None,\r\n",
      "                 ax=None, fig=None, title=None, xlim=None, ylim=None,\r\n",
      "                 xticks=None, yticks=None,\r\n",
      "                 sort_columns=False, fontsize=None,\r\n",
      "                 secondary_y=False, colormap=None,\r\n",
      "                 table=False, layout=None, **kwds):\r\n",
      "\r\n",
      "        _converter._WARN = False\r\n",
      "        self.data = data\r\n",
      "        self.by = by\r\n",
      "\r\n",
      "        self.kind = kind\r\n",
      "\r\n",
      "        self.sort_columns = sort_columns\r\n",
      "\r\n",
      "        self.subplots = subplots\r\n",
      "\r\n",
      "        if sharex is None:\r\n",
      "            if ax is None:\r\n",
      "                self.sharex = True\r\n",
      "            else:\r\n",
      "                # if we get an axis, the users should do the visibility\r\n",
      "                # setting...\r\n",
      "                self.sharex = False\r\n",
      "        else:\r\n",
      "            self.sharex = sharex\r\n",
      "\r\n",
      "        self.sharey = sharey\r\n",
      "        self.figsize = figsize\r\n",
      "        self.layout = layout\r\n",
      "\r\n",
      "        self.xticks = xticks\r\n",
      "        self.yticks = yticks\r\n",
      "        self.xlim = xlim\r\n",
      "        self.ylim = ylim\r\n",
      "        self.title = title\r\n",
      "        self.use_index = use_index\r\n",
      "\r\n",
      "        self.fontsize = fontsize\r\n",
      "\r\n",
      "        if rot is not None:\r\n",
      "            self.rot = rot\r\n",
      "            # need to know for format_date_labels since it's rotated to 30 by\r\n",
      "            # default\r\n",
      "            self._rot_set = True\r\n",
      "        else:\r\n",
      "            self._rot_set = False\r\n",
      "            self.rot = self._default_rot\r\n",
      "\r\n",
      "        if grid is None:\r\n",
      "            grid = False if secondary_y else self.plt.rcParams['axes.grid']\r\n",
      "\r\n",
      "        self.grid = grid\r\n",
      "        self.legend = legend\r\n",
      "        self.legend_handles = []\r\n",
      "        self.legend_labels = []\r\n",
      "\r\n",
      "        for attr in self._pop_attributes:\r\n",
      "            value = kwds.pop(attr, self._attr_defaults.get(attr, None))\r\n",
      "            setattr(self, attr, value)\r\n",
      "\r\n",
      "        self.ax = ax\r\n",
      "        self.fig = fig\r\n",
      "        self.axes = None\r\n",
      "\r\n",
      "        # parse errorbar input if given\r\n",
      "        xerr = kwds.pop('xerr', None)\r\n",
      "        yerr = kwds.pop('yerr', None)\r\n",
      "        self.errors = {}\r\n",
      "        for kw, err in zip(['xerr', 'yerr'], [xerr, yerr]):\r\n",
      "            self.errors[kw] = self._parse_errorbars(kw, err)\r\n",
      "\r\n",
      "        if not isinstance(secondary_y, (bool, tuple, list, np.ndarray, Index)):\r\n",
      "            secondary_y = [secondary_y]\r\n",
      "        self.secondary_y = secondary_y\r\n",
      "\r\n",
      "        # ugly TypeError if user passes matplotlib's `cmap` name.\r\n",
      "        # Probably better to accept either.\r\n",
      "        if 'cmap' in kwds and colormap:\r\n",
      "            raise TypeError(\"Only specify one of `cmap` and `colormap`.\")\r\n",
      "        elif 'cmap' in kwds:\r\n",
      "            self.colormap = kwds.pop('cmap')\r\n",
      "        else:\r\n",
      "            self.colormap = colormap\r\n",
      "\r\n",
      "        self.table = table\r\n",
      "\r\n",
      "        self.kwds = kwds\r\n",
      "\r\n",
      "        self._validate_color_args()\r\n",
      "\r\n",
      "    def _validate_color_args(self):\r\n",
      "        if 'color' not in self.kwds and 'colors' in self.kwds:\r\n",
      "            warnings.warn((\"'colors' is being deprecated. Please use 'color'\"\r\n",
      "                           \"instead of 'colors'\"))\r\n",
      "            colors = self.kwds.pop('colors')\r\n",
      "            self.kwds['color'] = colors\r\n",
      "\r\n",
      "        if ('color' in self.kwds and self.nseries == 1 and\r\n",
      "                not is_list_like(self.kwds['color'])):\r\n",
      "            # support series.plot(color='green')\r\n",
      "            self.kwds['color'] = [self.kwds['color']]\r\n",
      "\r\n",
      "        if ('color' in self.kwds and isinstance(self.kwds['color'], tuple) and\r\n",
      "                self.nseries == 1 and len(self.kwds['color']) in (3, 4)):\r\n",
      "            # support RGB and RGBA tuples in series plot\r\n",
      "            self.kwds['color'] = [self.kwds['color']]\r\n",
      "\r\n",
      "        if ('color' in self.kwds or 'colors' in self.kwds) and \\\r\n",
      "                self.colormap is not None:\r\n",
      "            warnings.warn(\"'color' and 'colormap' cannot be used \"\r\n",
      "                          \"simultaneously. Using 'color'\")\r\n",
      "\r\n",
      "        if 'color' in self.kwds and self.style is not None:\r\n",
      "            if is_list_like(self.style):\r\n",
      "                styles = self.style\r\n",
      "            else:\r\n",
      "                styles = [self.style]\r\n",
      "            # need only a single match\r\n",
      "            for s in styles:\r\n",
      "                if re.match('^[a-z]+?', s) is not None:\r\n",
      "                    raise ValueError(\r\n",
      "                        \"Cannot pass 'style' string with a color \"\r\n",
      "                        \"symbol and 'color' keyword argument. Please\"\r\n",
      "                        \" use one or the other or pass 'style' \"\r\n",
      "                        \"without a color symbol\")\r\n",
      "\r\n",
      "    def _iter_data(self, data=None, keep_index=False, fillna=None):\r\n",
      "        if data is None:\r\n",
      "            data = self.data\r\n",
      "        if fillna is not None:\r\n",
      "            data = data.fillna(fillna)\r\n",
      "\r\n",
      "        # TODO: unused?\r\n",
      "        # if self.sort_columns:\r\n",
      "        #     columns = _try_sort(data.columns)\r\n",
      "        # else:\r\n",
      "        #     columns = data.columns\r\n",
      "\r\n",
      "        for col, values in data.iteritems():\r\n",
      "            if keep_index is True:\r\n",
      "                yield col, values\r\n",
      "            else:\r\n",
      "                yield col, values.values\r\n",
      "\r\n",
      "    @property\r\n",
      "    def nseries(self):\r\n",
      "        if self.data.ndim == 1:\r\n",
      "            return 1\r\n",
      "        else:\r\n",
      "            return self.data.shape[1]\r\n",
      "\r\n",
      "    def draw(self):\r\n",
      "        self.plt.draw_if_interactive()\r\n",
      "\r\n",
      "    def generate(self):\r\n",
      "        self._args_adjust()\r\n",
      "        self._compute_plot_data()\r\n",
      "        self._setup_subplots()\r\n",
      "        self._make_plot()\r\n",
      "        self._add_table()\r\n",
      "        self._make_legend()\r\n",
      "        self._adorn_subplots()\r\n",
      "\r\n",
      "        for ax in self.axes:\r\n",
      "            self._post_plot_logic_common(ax, self.data)\r\n",
      "            self._post_plot_logic(ax, self.data)\r\n",
      "\r\n",
      "    def _args_adjust(self):\r\n",
      "        pass\r\n",
      "\r\n",
      "    def _has_plotted_object(self, ax):\r\n",
      "        \"\"\"check whether ax has data\"\"\"\r\n",
      "        return (len(ax.lines) != 0 or\r\n",
      "                len(ax.artists) != 0 or\r\n",
      "                len(ax.containers) != 0)\r\n",
      "\r\n",
      "    def _maybe_right_yaxis(self, ax, axes_num):\r\n",
      "        if not self.on_right(axes_num):\r\n",
      "            # secondary axes may be passed via ax kw\r\n",
      "            return self._get_ax_layer(ax)\r\n",
      "\r\n",
      "        if hasattr(ax, 'right_ax'):\r\n",
      "            # if it has right_ax proparty, ``ax`` must be left axes\r\n",
      "            return ax.right_ax\r\n",
      "        elif hasattr(ax, 'left_ax'):\r\n",
      "            # if it has left_ax proparty, ``ax`` must be right axes\r\n",
      "            return ax\r\n",
      "        else:\r\n",
      "            # otherwise, create twin axes\r\n",
      "            orig_ax, new_ax = ax, ax.twinx()\r\n",
      "            # TODO: use Matplotlib public API when available\r\n",
      "            new_ax._get_lines = orig_ax._get_lines\r\n",
      "            new_ax._get_patches_for_fill = orig_ax._get_patches_for_fill\r\n",
      "            orig_ax.right_ax, new_ax.left_ax = new_ax, orig_ax\r\n",
      "\r\n",
      "            if not self._has_plotted_object(orig_ax):  # no data on left y\r\n",
      "                orig_ax.get_yaxis().set_visible(False)\r\n",
      "            return new_ax\r\n",
      "\r\n",
      "    def _setup_subplots(self):\r\n",
      "        if self.subplots:\r\n",
      "            fig, axes = _subplots(naxes=self.nseries,\r\n",
      "                                  sharex=self.sharex, sharey=self.sharey,\r\n",
      "                                  figsize=self.figsize, ax=self.ax,\r\n",
      "                                  layout=self.layout,\r\n",
      "                                  layout_type=self._layout_type)\r\n",
      "        else:\r\n",
      "            if self.ax is None:\r\n",
      "                fig = self.plt.figure(figsize=self.figsize)\r\n",
      "                axes = fig.add_subplot(111)\r\n",
      "            else:\r\n",
      "                fig = self.ax.get_figure()\r\n",
      "                if self.figsize is not None:\r\n",
      "                    fig.set_size_inches(self.figsize)\r\n",
      "                axes = self.ax\r\n",
      "\r\n",
      "        axes = _flatten(axes)\r\n",
      "\r\n",
      "        if self.logx or self.loglog:\r\n",
      "            [a.set_xscale('log') for a in axes]\r\n",
      "        if self.logy or self.loglog:\r\n",
      "            [a.set_yscale('log') for a in axes]\r\n",
      "\r\n",
      "        self.fig = fig\r\n",
      "        self.axes = axes\r\n",
      "\r\n",
      "    @property\r\n",
      "    def result(self):\r\n",
      "        \"\"\"\r\n",
      "        Return result axes\r\n",
      "        \"\"\"\r\n",
      "        if self.subplots:\r\n",
      "            if self.layout is not None and not is_list_like(self.ax):\r\n",
      "                return self.axes.reshape(*self.layout)\r\n",
      "            else:\r\n",
      "                return self.axes\r\n",
      "        else:\r\n",
      "            sec_true = isinstance(self.secondary_y, bool) and self.secondary_y\r\n",
      "            all_sec = (is_list_like(self.secondary_y) and\r\n",
      "                       len(self.secondary_y) == self.nseries)\r\n",
      "            if (sec_true or all_sec):\r\n",
      "                # if all data is plotted on secondary, return right axes\r\n",
      "                return self._get_ax_layer(self.axes[0], primary=False)\r\n",
      "            else:\r\n",
      "                return self.axes[0]\r\n",
      "\r\n",
      "    def _compute_plot_data(self):\r\n",
      "        data = self.data\r\n",
      "\r\n",
      "        if isinstance(data, ABCSeries):\r\n",
      "            label = self.label\r\n",
      "            if label is None and data.name is None:\r\n",
      "                label = 'None'\r\n",
      "            data = data.to_frame(name=label)\r\n",
      "\r\n",
      "        # GH16953, _convert is needed as fallback, for ``Series``\r\n",
      "        # with ``dtype == object``\r\n",
      "        data = data._convert(datetime=True, timedelta=True)\r\n",
      "        numeric_data = data.select_dtypes(include=[np.number,\r\n",
      "                                                   \"datetime\",\r\n",
      "                                                   \"datetimetz\",\r\n",
      "                                                   \"timedelta\"])\r\n",
      "\r\n",
      "        try:\r\n",
      "            is_empty = numeric_data.empty\r\n",
      "        except AttributeError:\r\n",
      "            is_empty = not len(numeric_data)\r\n",
      "\r\n",
      "        # no empty frames or series allowed\r\n",
      "        if is_empty:\r\n",
      "            raise TypeError('Empty {0!r}: no numeric data to '\r\n",
      "                            'plot'.format(numeric_data.__class__.__name__))\r\n",
      "\r\n",
      "        self.data = numeric_data\r\n",
      "\r\n",
      "    def _make_plot(self):\r\n",
      "        raise AbstractMethodError(self)\r\n",
      "\r\n",
      "    def _add_table(self):\r\n",
      "        if self.table is False:\r\n",
      "            return\r\n",
      "        elif self.table is True:\r\n",
      "            data = self.data.transpose()\r\n",
      "        else:\r\n",
      "            data = self.table\r\n",
      "        ax = self._get_ax(0)\r\n",
      "        table(ax, data)\r\n",
      "\r\n",
      "    def _post_plot_logic_common(self, ax, data):\r\n",
      "        \"\"\"Common post process for each axes\"\"\"\r\n",
      "\r\n",
      "        def get_label(i):\r\n",
      "            try:\r\n",
      "                return pprint_thing(data.index[i])\r\n",
      "            except Exception:\r\n",
      "                return ''\r\n",
      "\r\n",
      "        if self.orientation == 'vertical' or self.orientation is None:\r\n",
      "            if self._need_to_set_index:\r\n",
      "                xticklabels = [get_label(x) for x in ax.get_xticks()]\r\n",
      "                ax.set_xticklabels(xticklabels)\r\n",
      "            self._apply_axis_properties(ax.xaxis, rot=self.rot,\r\n",
      "                                        fontsize=self.fontsize)\r\n",
      "            self._apply_axis_properties(ax.yaxis, fontsize=self.fontsize)\r\n",
      "\r\n",
      "            if hasattr(ax, 'right_ax'):\r\n",
      "                self._apply_axis_properties(ax.right_ax.yaxis,\r\n",
      "                                            fontsize=self.fontsize)\r\n",
      "\r\n",
      "        elif self.orientation == 'horizontal':\r\n",
      "            if self._need_to_set_index:\r\n",
      "                yticklabels = [get_label(y) for y in ax.get_yticks()]\r\n",
      "                ax.set_yticklabels(yticklabels)\r\n",
      "            self._apply_axis_properties(ax.yaxis, rot=self.rot,\r\n",
      "                                        fontsize=self.fontsize)\r\n",
      "            self._apply_axis_properties(ax.xaxis, fontsize=self.fontsize)\r\n",
      "\r\n",
      "            if hasattr(ax, 'right_ax'):\r\n",
      "                self._apply_axis_properties(ax.right_ax.yaxis,\r\n",
      "                                            fontsize=self.fontsize)\r\n",
      "        else:  # pragma no cover\r\n",
      "            raise ValueError\r\n",
      "\r\n",
      "    def _post_plot_logic(self, ax, data):\r\n",
      "        \"\"\"Post process for each axes. Overridden in child classes\"\"\"\r\n",
      "        pass\r\n",
      "\r\n",
      "    def _adorn_subplots(self):\r\n",
      "        \"\"\"Common post process unrelated to data\"\"\"\r\n",
      "        if len(self.axes) > 0:\r\n",
      "            all_axes = self._get_subplots()\r\n",
      "            nrows, ncols = self._get_axes_layout()\r\n",
      "            _handle_shared_axes(axarr=all_axes, nplots=len(all_axes),\r\n",
      "                                naxes=nrows * ncols, nrows=nrows,\r\n",
      "                                ncols=ncols, sharex=self.sharex,\r\n",
      "                                sharey=self.sharey)\r\n",
      "\r\n",
      "        for ax in self.axes:\r\n",
      "            if self.yticks is not None:\r\n",
      "                ax.set_yticks(self.yticks)\r\n",
      "\r\n",
      "            if self.xticks is not None:\r\n",
      "                ax.set_xticks(self.xticks)\r\n",
      "\r\n",
      "            if self.ylim is not None:\r\n",
      "                ax.set_ylim(self.ylim)\r\n",
      "\r\n",
      "            if self.xlim is not None:\r\n",
      "                ax.set_xlim(self.xlim)\r\n",
      "\r\n",
      "            ax.grid(self.grid)\r\n",
      "\r\n",
      "        if self.title:\r\n",
      "            if self.subplots:\r\n",
      "                if is_list_like(self.title):\r\n",
      "                    if len(self.title) != self.nseries:\r\n",
      "                        msg = ('The length of `title` must equal the number '\r\n",
      "                               'of columns if using `title` of type `list` '\r\n",
      "                               'and `subplots=True`.\\n'\r\n",
      "                               'length of title = {}\\n'\r\n",
      "                               'number of columns = {}').format(\r\n",
      "                            len(self.title), self.nseries)\r\n",
      "                        raise ValueError(msg)\r\n",
      "\r\n",
      "                    for (ax, title) in zip(self.axes, self.title):\r\n",
      "                        ax.set_title(title)\r\n",
      "                else:\r\n",
      "                    self.fig.suptitle(self.title)\r\n",
      "            else:\r\n",
      "                if is_list_like(self.title):\r\n",
      "                    msg = ('Using `title` of type `list` is not supported '\r\n",
      "                           'unless `subplots=True` is passed')\r\n",
      "                    raise ValueError(msg)\r\n",
      "                self.axes[0].set_title(self.title)\r\n",
      "\r\n",
      "    def _apply_axis_properties(self, axis, rot=None, fontsize=None):\r\n",
      "        labels = axis.get_majorticklabels() + axis.get_minorticklabels()\r\n",
      "        for label in labels:\r\n",
      "            if rot is not None:\r\n",
      "                label.set_rotation(rot)\r\n",
      "            if fontsize is not None:\r\n",
      "                label.set_fontsize(fontsize)\r\n",
      "\r\n",
      "    @property\r\n",
      "    def legend_title(self):\r\n",
      "        if not isinstance(self.data.columns, MultiIndex):\r\n",
      "            name = self.data.columns.name\r\n",
      "            if name is not None:\r\n",
      "                name = pprint_thing(name)\r\n",
      "            return name\r\n",
      "        else:\r\n",
      "            stringified = map(pprint_thing,\r\n",
      "                              self.data.columns.names)\r\n",
      "            return ','.join(stringified)\r\n",
      "\r\n",
      "    def _add_legend_handle(self, handle, label, index=None):\r\n",
      "        if label is not None:\r\n",
      "            if self.mark_right and index is not None:\r\n",
      "                if self.on_right(index):\r\n",
      "                    label = label + ' (right)'\r\n",
      "            self.legend_handles.append(handle)\r\n",
      "            self.legend_labels.append(label)\r\n",
      "\r\n",
      "    def _make_legend(self):\r\n",
      "        ax, leg = self._get_ax_legend(self.axes[0])\r\n",
      "\r\n",
      "        handles = []\r\n",
      "        labels = []\r\n",
      "        title = ''\r\n",
      "\r\n",
      "        if not self.subplots:\r\n",
      "            if leg is not None:\r\n",
      "                title = leg.get_title().get_text()\r\n",
      "                handles = leg.legendHandles\r\n",
      "                labels = [x.get_text() for x in leg.get_texts()]\r\n",
      "\r\n",
      "            if self.legend:\r\n",
      "                if self.legend == 'reverse':\r\n",
      "                    self.legend_handles = reversed(self.legend_handles)\r\n",
      "                    self.legend_labels = reversed(self.legend_labels)\r\n",
      "\r\n",
      "                handles += self.legend_handles\r\n",
      "                labels += self.legend_labels\r\n",
      "                if self.legend_title is not None:\r\n",
      "                    title = self.legend_title\r\n",
      "\r\n",
      "            if len(handles) > 0:\r\n",
      "                ax.legend(handles, labels, loc='best', title=title)\r\n",
      "\r\n",
      "        elif self.subplots and self.legend:\r\n",
      "            for ax in self.axes:\r\n",
      "                if ax.get_visible():\r\n",
      "                    ax.legend(loc='best')\r\n",
      "\r\n",
      "    def _get_ax_legend(self, ax):\r\n",
      "        leg = ax.get_legend()\r\n",
      "        other_ax = (getattr(ax, 'left_ax', None) or\r\n",
      "                    getattr(ax, 'right_ax', None))\r\n",
      "        other_leg = None\r\n",
      "        if other_ax is not None:\r\n",
      "            other_leg = other_ax.get_legend()\r\n",
      "        if leg is None and other_leg is not None:\r\n",
      "            leg = other_leg\r\n",
      "            ax = other_ax\r\n",
      "        return ax, leg\r\n",
      "\r\n",
      "    @cache_readonly\r\n",
      "    def plt(self):\r\n",
      "        import matplotlib.pyplot as plt\r\n",
      "        return plt\r\n",
      "\r\n",
      "    @staticmethod\r\n",
      "    def mpl_ge_1_3_1():\r\n",
      "        return _mpl_ge_1_3_1()\r\n",
      "\r\n",
      "    @staticmethod\r\n",
      "    def mpl_ge_1_5_0():\r\n",
      "        return _mpl_ge_1_5_0()\r\n",
      "\r\n",
      "    _need_to_set_index = False\r\n",
      "\r\n",
      "    def _get_xticks(self, convert_period=False):\r\n",
      "        index = self.data.index\r\n",
      "        is_datetype = index.inferred_type in ('datetime', 'date',\r\n",
      "                                              'datetime64', 'time')\r\n",
      "\r\n",
      "        if self.use_index:\r\n",
      "            if convert_period and isinstance(index, PeriodIndex):\r\n",
      "                self.data = self.data.reindex(index=index.sort_values())\r\n",
      "                x = self.data.index.to_timestamp()._mpl_repr()\r\n",
      "            elif index.is_numeric():\r\n",
      "                \"\"\"\r\n",
      "                Matplotlib supports numeric values or datetime objects as\r\n",
      "                xaxis values. Taking LBYL approach here, by the time\r\n",
      "                matplotlib raises exception when using non numeric/datetime\r\n",
      "                values for xaxis, several actions are already taken by plt.\r\n",
      "                \"\"\"\r\n",
      "                x = index._mpl_repr()\r\n",
      "            elif is_datetype:\r\n",
      "                self.data = self.data[notna(self.data.index)]\r\n",
      "                self.data = self.data.sort_index()\r\n",
      "                x = self.data.index._mpl_repr()\r\n",
      "            else:\r\n",
      "                self._need_to_set_index = True\r\n",
      "                x = lrange(len(index))\r\n",
      "        else:\r\n",
      "            x = lrange(len(index))\r\n",
      "\r\n",
      "        return x\r\n",
      "\r\n",
      "    @classmethod\r\n",
      "    def _plot(cls, ax, x, y, style=None, is_errorbar=False, **kwds):\r\n",
      "        mask = isna(y)\r\n",
      "        if mask.any():\r\n",
      "            y = np.ma.array(y)\r\n",
      "            y = np.ma.masked_where(mask, y)\r\n",
      "\r\n",
      "        if isinstance(x, Index):\r\n",
      "            x = x._mpl_repr()\r\n",
      "\r\n",
      "        if is_errorbar:\r\n",
      "            if 'xerr' in kwds:\r\n",
      "                kwds['xerr'] = np.array(kwds.get('xerr'))\r\n",
      "            if 'yerr' in kwds:\r\n",
      "                kwds['yerr'] = np.array(kwds.get('yerr'))\r\n",
      "            return ax.errorbar(x, y, **kwds)\r\n",
      "        else:\r\n",
      "            # prevent style kwarg from going to errorbar, where it is\r\n",
      "            # unsupported\r\n",
      "            if style is not None:\r\n",
      "                args = (x, y, style)\r\n",
      "            else:\r\n",
      "                args = (x, y)\r\n",
      "            return ax.plot(*args, **kwds)\r\n",
      "\r\n",
      "    def _get_index_name(self):\r\n",
      "        if isinstance(self.data.index, MultiIndex):\r\n",
      "            name = self.data.index.names\r\n",
      "            if _any_not_none(*name):\r\n",
      "                name = ','.join([pprint_thing(x) for x in name])\r\n",
      "            else:\r\n",
      "                name = None\r\n",
      "        else:\r\n",
      "            name = self.data.index.name\r\n",
      "            if name is not None:\r\n",
      "                name = pprint_thing(name)\r\n",
      "\r\n",
      "        return name\r\n",
      "\r\n",
      "    @classmethod\r\n",
      "    def _get_ax_layer(cls, ax, primary=True):\r\n",
      "        \"\"\"get left (primary) or right (secondary) axes\"\"\"\r\n",
      "        if primary:\r\n",
      "            return getattr(ax, 'left_ax', ax)\r\n",
      "        else:\r\n",
      "            return getattr(ax, 'right_ax', ax)\r\n",
      "\r\n",
      "    def _get_ax(self, i):\r\n",
      "        # get the twinx ax if appropriate\r\n",
      "        if self.subplots:\r\n",
      "            ax = self.axes[i]\r\n",
      "            ax = self._maybe_right_yaxis(ax, i)\r\n",
      "            self.axes[i] = ax\r\n",
      "        else:\r\n",
      "            ax = self.axes[0]\r\n",
      "            ax = self._maybe_right_yaxis(ax, i)\r\n",
      "\r\n",
      "        ax.get_yaxis().set_visible(True)\r\n",
      "        return ax\r\n",
      "\r\n",
      "    def on_right(self, i):\r\n",
      "        if isinstance(self.secondary_y, bool):\r\n",
      "            return self.secondary_y\r\n",
      "\r\n",
      "        if isinstance(self.secondary_y, (tuple, list, np.ndarray, Index)):\r\n",
      "            return self.data.columns[i] in self.secondary_y\r\n",
      "\r\n",
      "    def _apply_style_colors(self, colors, kwds, col_num, label):\r\n",
      "        \"\"\"\r\n",
      "        Manage style and color based on column number and its label.\r\n",
      "        Returns tuple of appropriate style and kwds which \"color\" may be added.\r\n",
      "        \"\"\"\r\n",
      "        style = None\r\n",
      "        if self.style is not None:\r\n",
      "            if isinstance(self.style, list):\r\n",
      "                try:\r\n",
      "                    style = self.style[col_num]\r\n",
      "                except IndexError:\r\n",
      "                    pass\r\n",
      "            elif isinstance(self.style, dict):\r\n",
      "                style = self.style.get(label, style)\r\n",
      "            else:\r\n",
      "                style = self.style\r\n",
      "\r\n",
      "        has_color = 'color' in kwds or self.colormap is not None\r\n",
      "        nocolor_style = style is None or re.match('[a-z]+', style) is None\r\n",
      "        if (has_color or self.subplots) and nocolor_style:\r\n",
      "            kwds['color'] = colors[col_num % len(colors)]\r\n",
      "        return style, kwds\r\n",
      "\r\n",
      "    def _get_colors(self, num_colors=None, color_kwds='color'):\r\n",
      "        if num_colors is None:\r\n",
      "            num_colors = self.nseries\r\n",
      "\r\n",
      "        return _get_standard_colors(num_colors=num_colors,\r\n",
      "                                    colormap=self.colormap,\r\n",
      "                                    color=self.kwds.get(color_kwds))\r\n",
      "\r\n",
      "    def _parse_errorbars(self, label, err):\r\n",
      "        \"\"\"\r\n",
      "        Look for error keyword arguments and return the actual errorbar data\r\n",
      "        or return the error DataFrame/dict\r\n",
      "\r\n",
      "        Error bars can be specified in several ways:\r\n",
      "            Series: the user provides a pandas.Series object of the same\r\n",
      "                    length as the data\r\n",
      "            ndarray: provides a np.ndarray of the same length as the data\r\n",
      "            DataFrame/dict: error values are paired with keys matching the\r\n",
      "                    key in the plotted DataFrame\r\n",
      "            str: the name of the column within the plotted DataFrame\r\n",
      "        \"\"\"\r\n",
      "\r\n",
      "        if err is None:\r\n",
      "            return None\r\n",
      "\r\n",
      "        from pandas import DataFrame, Series\r\n",
      "\r\n",
      "        def match_labels(data, e):\r\n",
      "            e = e.reindex(data.index)\r\n",
      "            return e\r\n",
      "\r\n",
      "        # key-matched DataFrame\r\n",
      "        if isinstance(err, DataFrame):\r\n",
      "\r\n",
      "            err = match_labels(self.data, err)\r\n",
      "        # key-matched dict\r\n",
      "        elif isinstance(err, dict):\r\n",
      "            pass\r\n",
      "\r\n",
      "        # Series of error values\r\n",
      "        elif isinstance(err, Series):\r\n",
      "            # broadcast error series across data\r\n",
      "            err = match_labels(self.data, err)\r\n",
      "            err = np.atleast_2d(err)\r\n",
      "            err = np.tile(err, (self.nseries, 1))\r\n",
      "\r\n",
      "        # errors are a column in the dataframe\r\n",
      "        elif isinstance(err, string_types):\r\n",
      "            evalues = self.data[err].values\r\n",
      "            self.data = self.data[self.data.columns.drop(err)]\r\n",
      "            err = np.atleast_2d(evalues)\r\n",
      "            err = np.tile(err, (self.nseries, 1))\r\n",
      "\r\n",
      "        elif is_list_like(err):\r\n",
      "            if is_iterator(err):\r\n",
      "                err = np.atleast_2d(list(err))\r\n",
      "            else:\r\n",
      "                # raw error values\r\n",
      "                err = np.atleast_2d(err)\r\n",
      "\r\n",
      "            err_shape = err.shape\r\n",
      "\r\n",
      "            # asymmetrical error bars\r\n",
      "            if err.ndim == 3:\r\n",
      "                if (err_shape[0] != self.nseries) or \\\r\n",
      "                        (err_shape[1] != 2) or \\\r\n",
      "                        (err_shape[2] != len(self.data)):\r\n",
      "                    msg = \"Asymmetrical error bars should be provided \" + \\\r\n",
      "                        \"with the shape (%u, 2, %u)\" % \\\r\n",
      "                        (self.nseries, len(self.data))\r\n",
      "                    raise ValueError(msg)\r\n",
      "\r\n",
      "            # broadcast errors to each data series\r\n",
      "            if len(err) == 1:\r\n",
      "                err = np.tile(err, (self.nseries, 1))\r\n",
      "\r\n",
      "        elif is_number(err):\r\n",
      "            err = np.tile([err], (self.nseries, len(self.data)))\r\n",
      "\r\n",
      "        else:\r\n",
      "            msg = \"No valid %s detected\" % label\r\n",
      "            raise ValueError(msg)\r\n",
      "\r\n",
      "        return err\r\n",
      "\r\n",
      "    def _get_errorbars(self, label=None, index=None, xerr=True, yerr=True):\r\n",
      "        from pandas import DataFrame\r\n",
      "        errors = {}\r\n",
      "\r\n",
      "        for kw, flag in zip(['xerr', 'yerr'], [xerr, yerr]):\r\n",
      "            if flag:\r\n",
      "                err = self.errors[kw]\r\n",
      "                # user provided label-matched dataframe of errors\r\n",
      "                if isinstance(err, (DataFrame, dict)):\r\n",
      "                    if label is not None and label in err.keys():\r\n",
      "                        err = err[label]\r\n",
      "                    else:\r\n",
      "                        err = None\r\n",
      "                elif index is not None and err is not None:\r\n",
      "                    err = err[index]\r\n",
      "\r\n",
      "                if err is not None:\r\n",
      "                    errors[kw] = err\r\n",
      "        return errors\r\n",
      "\r\n",
      "    def _get_subplots(self):\r\n",
      "        from matplotlib.axes import Subplot\r\n",
      "        return [ax for ax in self.axes[0].get_figure().get_axes()\r\n",
      "                if isinstance(ax, Subplot)]\r\n",
      "\r\n",
      "    def _get_axes_layout(self):\r\n",
      "        axes = self._get_subplots()\r\n",
      "        x_set = set()\r\n",
      "        y_set = set()\r\n",
      "        for ax in axes:\r\n",
      "            # check axes coordinates to estimate layout\r\n",
      "            points = ax.get_position().get_points()\r\n",
      "            x_set.add(points[0][0])\r\n",
      "            y_set.add(points[0][1])\r\n",
      "        return (len(y_set), len(x_set))\r\n",
      "\r\n",
      "\r\n",
      "class PlanePlot(MPLPlot):\r\n",
      "    \"\"\"\r\n",
      "    Abstract class for plotting on plane, currently scatter and hexbin.\r\n",
      "    \"\"\"\r\n",
      "\r\n",
      "    _layout_type = 'single'\r\n",
      "\r\n",
      "    def __init__(self, data, x, y, **kwargs):\r\n",
      "        MPLPlot.__init__(self, data, **kwargs)\r\n",
      "        if x is None or y is None:\r\n",
      "            raise ValueError(self._kind + ' requires and x and y column')\r\n",
      "        if is_integer(x) and not self.data.columns.holds_integer():\r\n",
      "            x = self.data.columns[x]\r\n",
      "        if is_integer(y) and not self.data.columns.holds_integer():\r\n",
      "            y = self.data.columns[y]\r\n",
      "        if len(self.data[x]._get_numeric_data()) == 0:\r\n",
      "            raise ValueError(self._kind + ' requires x column to be numeric')\r\n",
      "        if len(self.data[y]._get_numeric_data()) == 0:\r\n",
      "            raise ValueError(self._kind + ' requires y column to be numeric')\r\n",
      "\r\n",
      "        self.x = x\r\n",
      "        self.y = y\r\n",
      "\r\n",
      "    @property\r\n",
      "    def nseries(self):\r\n",
      "        return 1\r\n",
      "\r\n",
      "    def _post_plot_logic(self, ax, data):\r\n",
      "        x, y = self.x, self.y\r\n",
      "        ax.set_ylabel(pprint_thing(y))\r\n",
      "        ax.set_xlabel(pprint_thing(x))\r\n",
      "\r\n",
      "\r\n",
      "class ScatterPlot(PlanePlot):\r\n",
      "    _kind = 'scatter'\r\n",
      "\r\n",
      "    def __init__(self, data, x, y, s=None, c=None, **kwargs):\r\n",
      "        if s is None:\r\n",
      "            # hide the matplotlib default for size, in case we want to change\r\n",
      "            # the handling of this argument later\r\n",
      "            s = 20\r\n",
      "        super(ScatterPlot, self).__init__(data, x, y, s=s, **kwargs)\r\n",
      "        if is_integer(c) and not self.data.columns.holds_integer():\r\n",
      "            c = self.data.columns[c]\r\n",
      "        self.c = c\r\n",
      "\r\n",
      "    def _make_plot(self):\r\n",
      "        x, y, c, data = self.x, self.y, self.c, self.data\r\n",
      "        ax = self.axes[0]\r\n",
      "\r\n",
      "        c_is_column = is_hashable(c) and c in self.data.columns\r\n",
      "\r\n",
      "        # plot a colorbar only if a colormap is provided or necessary\r\n",
      "        cb = self.kwds.pop('colorbar', self.colormap or c_is_column)\r\n",
      "\r\n",
      "        # pandas uses colormap, matplotlib uses cmap.\r\n",
      "        cmap = self.colormap or 'Greys'\r\n",
      "        cmap = self.plt.cm.get_cmap(cmap)\r\n",
      "        color = self.kwds.pop(\"color\", None)\r\n",
      "        if c is not None and color is not None:\r\n",
      "            raise TypeError('Specify exactly one of `c` and `color`')\r\n",
      "        elif c is None and color is None:\r\n",
      "            c_values = self.plt.rcParams['patch.facecolor']\r\n",
      "        elif color is not None:\r\n",
      "            c_values = color\r\n",
      "        elif c_is_column:\r\n",
      "            c_values = self.data[c].values\r\n",
      "        else:\r\n",
      "            c_values = c\r\n",
      "\r\n",
      "        if self.legend and hasattr(self, 'label'):\r\n",
      "            label = self.label\r\n",
      "        else:\r\n",
      "            label = None\r\n",
      "        scatter = ax.scatter(data[x].values, data[y].values, c=c_values,\r\n",
      "                             label=label, cmap=cmap, **self.kwds)\r\n",
      "        if cb:\r\n",
      "            img = ax.collections[0]\r\n",
      "            kws = dict(ax=ax)\r\n",
      "            if self.mpl_ge_1_3_1():\r\n",
      "                kws['label'] = c if c_is_column else ''\r\n",
      "            self.fig.colorbar(img, **kws)\r\n",
      "\r\n",
      "        if label is not None:\r\n",
      "            self._add_legend_handle(scatter, label)\r\n",
      "        else:\r\n",
      "            self.legend = False\r\n",
      "\r\n",
      "        errors_x = self._get_errorbars(label=x, index=0, yerr=False)\r\n",
      "        errors_y = self._get_errorbars(label=y, index=0, xerr=False)\r\n",
      "        if len(errors_x) > 0 or len(errors_y) > 0:\r\n",
      "            err_kwds = dict(errors_x, **errors_y)\r\n",
      "            err_kwds['ecolor'] = scatter.get_facecolor()[0]\r\n",
      "            ax.errorbar(data[x].values, data[y].values,\r\n",
      "                        linestyle='none', **err_kwds)\r\n",
      "\r\n",
      "\r\n",
      "class HexBinPlot(PlanePlot):\r\n",
      "    _kind = 'hexbin'\r\n",
      "\r\n",
      "    def __init__(self, data, x, y, C=None, **kwargs):\r\n",
      "        super(HexBinPlot, self).__init__(data, x, y, **kwargs)\r\n",
      "        if is_integer(C) and not self.data.columns.holds_integer():\r\n",
      "            C = self.data.columns[C]\r\n",
      "        self.C = C\r\n",
      "\r",
      "\r\n",
      "    def _make_plot(self):\r\n",
      "        x, y, data, C = self.x, self.y, self.data, self.C\r\n",
      "        ax = self.axes[0]\r\n",
      "        # pandas uses colormap, matplotlib uses cmap.\r\n",
      "        cmap = self.colormap or 'BuGn'\r\n",
      "        cmap = self.plt.cm.get_cmap(cmap)\r\n",
      "        cb = self.kwds.pop('colorbar', True)\r\n",
      "\r\n",
      "        if C is None:\r\n",
      "            c_values = None\r\n",
      "        else:\r\n",
      "            c_values = data[C].values\r\n",
      "\r\n",
      "        ax.hexbin(data[x].values, data[y].values, C=c_values, cmap=cmap,\r\n",
      "                  **self.kwds)\r\n",
      "        if cb:\r\n",
      "            img = ax.collections[0]\r\n",
      "            self.fig.colorbar(img, ax=ax)\r\n",
      "\r\n",
      "    def _make_legend(self):\r\n",
      "        pass\r\n",
      "\r\n",
      "\r\n",
      "class LinePlot(MPLPlot):\r\n",
      "    _kind = 'line'\r\n",
      "    _default_rot = 0\r\n",
      "    orientation = 'vertical'\r\n",
      "\r\n",
      "    def __init__(self, data, **kwargs):\r\n",
      "        MPLPlot.__init__(self, data, **kwargs)\r\n",
      "        if self.stacked:\r\n",
      "            self.data = self.data.fillna(value=0)\r\n",
      "        self.x_compat = plot_params['x_compat']\r\n",
      "        if 'x_compat' in self.kwds:\r\n",
      "            self.x_compat = bool(self.kwds.pop('x_compat'))\r\n",
      "\r\n",
      "    def _is_ts_plot(self):\r\n",
      "        # this is slightly deceptive\r\n",
      "        return not self.x_compat and self.use_index and self._use_dynamic_x()\r\n",
      "\r\n",
      "    def _use_dynamic_x(self):\r\n",
      "        from pandas.plotting._timeseries import _use_dynamic_x\r\n",
      "        return _use_dynamic_x(self._get_ax(0), self.data)\r\n",
      "\r\n",
      "    def _make_plot(self):\r\n",
      "        if self._is_ts_plot():\r\n",
      "            from pandas.plotting._timeseries import _maybe_convert_index\r\n",
      "            data = _maybe_convert_index(self._get_ax(0), self.data)\r\n",
      "\r\n",
      "            x = data.index      # dummy, not used\r\n",
      "            plotf = self._ts_plot\r\n",
      "            it = self._iter_data(data=data, keep_index=True)\r\n",
      "        else:\r\n",
      "            x = self._get_xticks(convert_period=True)\r\n",
      "            plotf = self._plot\r\n",
      "            it = self._iter_data()\r\n",
      "\r\n",
      "        stacking_id = self._get_stacking_id()\r\n",
      "        is_errorbar = _any_not_none(*self.errors.values())\r\n",
      "\r\n",
      "        colors = self._get_colors()\r\n",
      "        for i, (label, y) in enumerate(it):\r\n",
      "            ax = self._get_ax(i)\r\n",
      "            kwds = self.kwds.copy()\r\n",
      "            style, kwds = self._apply_style_colors(colors, kwds, i, label)\r\n",
      "\r\n",
      "            errors = self._get_errorbars(label=label, index=i)\r\n",
      "            kwds = dict(kwds, **errors)\r\n",
      "\r\n",
      "            label = pprint_thing(label)  # .encode('utf-8')\r\n",
      "            kwds['label'] = label\r\n",
      "\r\n",
      "            newlines = plotf(ax, x, y, style=style, column_num=i,\r\n",
      "                             stacking_id=stacking_id,\r\n",
      "                             is_errorbar=is_errorbar,\r\n",
      "                             **kwds)\r\n",
      "            self._add_legend_handle(newlines[0], label, index=i)\r\n",
      "\r\n",
      "            if not _mpl_ge_2_0_0():\r\n",
      "                lines = _get_all_lines(ax)\r\n",
      "                left, right = _get_xlim(lines)\r\n",
      "                ax.set_xlim(left, right)\r\n",
      "\r\n",
      "    @classmethod\r\n",
      "    def _plot(cls, ax, x, y, style=None, column_num=None,\r\n",
      "              stacking_id=None, **kwds):\r\n",
      "        # column_num is used to get the target column from protf in line and\r\n",
      "        # area plots\r\n",
      "        if column_num == 0:\r\n",
      "            cls._initialize_stacker(ax, stacking_id, len(y))\r\n",
      "        y_values = cls._get_stacked_values(ax, stacking_id, y, kwds['label'])\r\n",
      "        lines = MPLPlot._plot(ax, x, y_values, style=style, **kwds)\r\n",
      "        cls._update_stacker(ax, stacking_id, y)\r\n",
      "        return lines\r\n",
      "\r\n",
      "    @classmethod\r\n",
      "    def _ts_plot(cls, ax, x, data, style=None, **kwds):\r\n",
      "        from pandas.plotting._timeseries import (_maybe_resample,\r\n",
      "                                                 _decorate_axes,\r\n",
      "                                                 format_dateaxis)\r\n",
      "        # accept x to be consistent with normal plot func,\r\n",
      "        # x is not passed to tsplot as it uses data.index as x coordinate\r\n",
      "        # column_num must be in kwds for stacking purpose\r\n",
      "        freq, data = _maybe_resample(data, ax, kwds)\r\n",
      "\r\n",
      "        # Set ax with freq info\r\n",
      "        _decorate_axes(ax, freq, kwds)\r\n",
      "        # digging deeper\r\n",
      "        if hasattr(ax, 'left_ax'):\r\n",
      "            _decorate_axes(ax.left_ax, freq, kwds)\r\n",
      "        if hasattr(ax, 'right_ax'):\r\n",
      "            _decorate_axes(ax.right_ax, freq, kwds)\r\n",
      "        ax._plot_data.append((data, cls._kind, kwds))\r\n",
      "\r\n",
      "        lines = cls._plot(ax, data.index, data.values, style=style, **kwds)\r\n",
      "        # set date formatter, locators and rescale limits\r\n",
      "        format_dateaxis(ax, ax.freq, data.index)\r\n",
      "        return lines\r\n",
      "\r\n",
      "    def _get_stacking_id(self):\r\n",
      "        if self.stacked:\r\n",
      "            return id(self.data)\r\n",
      "        else:\r\n",
      "            return None\r\n",
      "\r\n",
      "    @classmethod\r\n",
      "    def _initialize_stacker(cls, ax, stacking_id, n):\r\n",
      "        if stacking_id is None:\r\n",
      "            return\r\n",
      "        if not hasattr(ax, '_stacker_pos_prior'):\r\n",
      "            ax._stacker_pos_prior = {}\r\n",
      "        if not hasattr(ax, '_stacker_neg_prior'):\r\n",
      "            ax._stacker_neg_prior = {}\r\n",
      "        ax._stacker_pos_prior[stacking_id] = np.zeros(n)\r\n",
      "        ax._stacker_neg_prior[stacking_id] = np.zeros(n)\r\n",
      "\r\n",
      "    @classmethod\r\n",
      "    def _get_stacked_values(cls, ax, stacking_id, values, label):\r\n",
      "        if stacking_id is None:\r\n",
      "            return values\r\n",
      "        if not hasattr(ax, '_stacker_pos_prior'):\r\n",
      "            # stacker may not be initialized for subplots\r\n",
      "            cls._initialize_stacker(ax, stacking_id, len(values))\r\n",
      "\r\n",
      "        if (values >= 0).all():\r\n",
      "            return ax._stacker_pos_prior[stacking_id] + values\r\n",
      "        elif (values <= 0).all():\r\n",
      "            return ax._stacker_neg_prior[stacking_id] + values\r\n",
      "\r\n",
      "        raise ValueError('When stacked is True, each column must be either '\r\n",
      "                         'all positive or negative.'\r\n",
      "                         '{0} contains both positive and negative values'\r\n",
      "                         .format(label))\r\n",
      "\r\n",
      "    @classmethod\r\n",
      "    def _update_stacker(cls, ax, stacking_id, values):\r\n",
      "        if stacking_id is None:\r\n",
      "            return\r\n",
      "        if (values >= 0).all():\r\n",
      "            ax._stacker_pos_prior[stacking_id] += values\r\n",
      "        elif (values <= 0).all():\r\n",
      "            ax._stacker_neg_prior[stacking_id] += values\r\n",
      "\r\n",
      "    def _post_plot_logic(self, ax, data):\r\n",
      "        condition = (not self._use_dynamic_x() and\r\n",
      "                     data.index.is_all_dates and\r\n",
      "                     not self.subplots or\r\n",
      "                     (self.subplots and self.sharex))\r\n",
      "\r\n",
      "        index_name = self._get_index_name()\r\n",
      "\r\n",
      "        if condition:\r\n",
      "            # irregular TS rotated 30 deg. by default\r\n",
      "            # probably a better place to check / set this.\r\n",
      "            if not self._rot_set:\r\n",
      "                self.rot = 30\r\n",
      "            format_date_labels(ax, rot=self.rot)\r\n",
      "\r\n",
      "        if index_name is not None and self.use_index:\r\n",
      "            ax.set_xlabel(index_name)\r\n",
      "\r\n",
      "\r\n",
      "class AreaPlot(LinePlot):\r\n",
      "    _kind = 'area'\r\n",
      "\r\n",
      "    def __init__(self, data, **kwargs):\r\n",
      "        kwargs.setdefault('stacked', True)\r\n",
      "        data = data.fillna(value=0)\r\n",
      "        LinePlot.__init__(self, data, **kwargs)\r\n",
      "\r\n",
      "        if not self.stacked:\r\n",
      "            # use smaller alpha to distinguish overlap\r\n",
      "            self.kwds.setdefault('alpha', 0.5)\r\n",
      "\r\n",
      "        if self.logy or self.loglog:\r\n",
      "            raise ValueError(\"Log-y scales are not supported in area plot\")\r\n",
      "\r\n",
      "    @classmethod\r\n",
      "    def _plot(cls, ax, x, y, style=None, column_num=None,\r\n",
      "              stacking_id=None, is_errorbar=False, **kwds):\r\n",
      "\r\n",
      "        if column_num == 0:\r\n",
      "            cls._initialize_stacker(ax, stacking_id, len(y))\r\n",
      "        y_values = cls._get_stacked_values(ax, stacking_id, y, kwds['label'])\r\n",
      "\r\n",
      "        # need to remove label, because subplots uses mpl legend as it is\r\n",
      "        line_kwds = kwds.copy()\r\n",
      "        if cls.mpl_ge_1_5_0():\r\n",
      "            line_kwds.pop('label')\r\n",
      "        lines = MPLPlot._plot(ax, x, y_values, style=style, **line_kwds)\r\n",
      "\r\n",
      "        # get data from the line to get coordinates for fill_between\r\n",
      "        xdata, y_values = lines[0].get_data(orig=False)\r\n",
      "\r\n",
      "        # unable to use ``_get_stacked_values`` here to get starting point\r\n",
      "        if stacking_id is None:\r\n",
      "            start = np.zeros(len(y))\r\n",
      "        elif (y >= 0).all():\r\n",
      "            start = ax._stacker_pos_prior[stacking_id]\r\n",
      "        elif (y <= 0).all():\r\n",
      "            start = ax._stacker_neg_prior[stacking_id]\r\n",
      "        else:\r\n",
      "            start = np.zeros(len(y))\r\n",
      "\r\n",
      "        if 'color' not in kwds:\r\n",
      "            kwds['color'] = lines[0].get_color()\r\n",
      "\r\n",
      "        rect = ax.fill_between(xdata, start, y_values, **kwds)\r\n",
      "        cls._update_stacker(ax, stacking_id, y)\r\n",
      "\r\n",
      "        # LinePlot expects list of artists\r\n",
      "        res = [rect] if cls.mpl_ge_1_5_0() else lines\r\n",
      "        return res\r\n",
      "\r\n",
      "    def _add_legend_handle(self, handle, label, index=None):\r\n",
      "        if not self.mpl_ge_1_5_0():\r\n",
      "            from matplotlib.patches import Rectangle\r\n",
      "            # Because fill_between isn't supported in legend,\r\n",
      "            # specifically add Rectangle handle here\r\n",
      "            alpha = self.kwds.get('alpha', None)\r\n",
      "            handle = Rectangle((0, 0), 1, 1, fc=handle.get_color(),\r\n",
      "                               alpha=alpha)\r\n",
      "        LinePlot._add_legend_handle(self, handle, label, index=index)\r\n",
      "\r\n",
      "    def _post_plot_logic(self, ax, data):\r\n",
      "        LinePlot._post_plot_logic(self, ax, data)\r\n",
      "\r\n",
      "        if self.ylim is None:\r\n",
      "            if (data >= 0).all().all():\r\n",
      "                ax.set_ylim(0, None)\r\n",
      "            elif (data <= 0).all().all():\r\n",
      "                ax.set_ylim(None, 0)\r\n",
      "\r\n",
      "\r\n",
      "class BarPlot(MPLPlot):\r\n",
      "    _kind = 'bar'\r\n",
      "    _default_rot = 90\r\n",
      "    orientation = 'vertical'\r\n",
      "\r\n",
      "    def __init__(self, data, **kwargs):\r\n",
      "        # we have to treat a series differently than a\r\n",
      "        # 1-column DataFrame w.r.t. color handling\r\n",
      "        self._is_series = isinstance(data, ABCSeries)\r\n",
      "        self.bar_width = kwargs.pop('width', 0.5)\r\n",
      "        pos = kwargs.pop('position', 0.5)\r\n",
      "        kwargs.setdefault('align', 'center')\r\n",
      "        self.tick_pos = np.arange(len(data))\r\n",
      "\r\n",
      "        self.bottom = kwargs.pop('bottom', 0)\r\n",
      "        self.left = kwargs.pop('left', 0)\r\n",
      "\r\n",
      "        self.log = kwargs.pop('log', False)\r\n",
      "        MPLPlot.__init__(self, data, **kwargs)\r\n",
      "\r\n",
      "        if self.stacked or self.subplots:\r\n",
      "            self.tickoffset = self.bar_width * pos\r\n",
      "            if kwargs['align'] == 'edge':\r",
      "\r\n",
      "                self.lim_offset = self.bar_width / 2\r\n",
      "            else:\r\n",
      "                self.lim_offset = 0\r\n",
      "        else:\r\n",
      "            if kwargs['align'] == 'edge':\r\n",
      "                w = self.bar_width / self.nseries\r\n",
      "                self.tickoffset = self.bar_width * (pos - 0.5) + w * 0.5\r\n",
      "                self.lim_offset = w * 0.5\r\n",
      "            else:\r\n",
      "                self.tickoffset = self.bar_width * pos\r\n",
      "                self.lim_offset = 0\r\n",
      "\r\n",
      "        self.ax_pos = self.tick_pos - self.tickoffset\r\n",
      "\r\n",
      "    def _args_adjust(self):\r\n",
      "        if is_list_like(self.bottom):\r\n",
      "            self.bottom = np.array(self.bottom)\r\n",
      "        if is_list_like(self.left):\r\n",
      "            self.left = np.array(self.left)\r\n",
      "\r\n",
      "    @classmethod\r\n",
      "    def _plot(cls, ax, x, y, w, start=0, log=False, **kwds):\r\n",
      "        return ax.bar(x, y, w, bottom=start, log=log, **kwds)\r\n",
      "\r\n",
      "    @property\r\n",
      "    def _start_base(self):\r\n",
      "        return self.bottom\r\n",
      "\r\n",
      "    def _make_plot(self):\r\n",
      "        import matplotlib as mpl\r\n",
      "\r\n",
      "        colors = self._get_colors()\r\n",
      "        ncolors = len(colors)\r\n",
      "\r\n",
      "        pos_prior = neg_prior = np.zeros(len(self.data))\r\n",
      "        K = self.nseries\r\n",
      "\r\n",
      "        for i, (label, y) in enumerate(self._iter_data(fillna=0)):\r\n",
      "            ax = self._get_ax(i)\r\n",
      "            kwds = self.kwds.copy()\r\n",
      "            if self._is_series:\r\n",
      "                kwds['color'] = colors\r\n",
      "            else:\r\n",
      "                kwds['color'] = colors[i % ncolors]\r\n",
      "\r\n",
      "            errors = self._get_errorbars(label=label, index=i)\r\n",
      "            kwds = dict(kwds, **errors)\r\n",
      "\r\n",
      "            label = pprint_thing(label)\r\n",
      "\r\n",
      "            if (('yerr' in kwds) or ('xerr' in kwds)) \\\r\n",
      "                    and (kwds.get('ecolor') is None):\r\n",
      "                kwds['ecolor'] = mpl.rcParams['xtick.color']\r\n",
      "\r\n",
      "            start = 0\r\n",
      "            if self.log and (y >= 1).all():\r\n",
      "                start = 1\r\n",
      "            start = start + self._start_base\r\n",
      "\r\n",
      "            if self.subplots:\r\n",
      "                w = self.bar_width / 2\r\n",
      "                rect = self._plot(ax, self.ax_pos + w, y, self.bar_width,\r\n",
      "                                  start=start, label=label,\r\n",
      "                                  log=self.log, **kwds)\r\n",
      "                ax.set_title(label)\r\n",
      "            elif self.stacked:\r\n",
      "                mask = y > 0\r\n",
      "                start = np.where(mask, pos_prior, neg_prior) + self._start_base\r\n",
      "                w = self.bar_width / 2\r\n",
      "                rect = self._plot(ax, self.ax_pos + w, y, self.bar_width,\r\n",
      "                                  start=start, label=label,\r\n",
      "                                  log=self.log, **kwds)\r\n",
      "                pos_prior = pos_prior + np.where(mask, y, 0)\r\n",
      "                neg_prior = neg_prior + np.where(mask, 0, y)\r\n",
      "            else:\r\n",
      "                w = self.bar_width / K\r\n",
      "                rect = self._plot(ax, self.ax_pos + (i + 0.5) * w, y, w,\r\n",
      "                                  start=start, label=label,\r\n",
      "                                  log=self.log, **kwds)\r\n",
      "            self._add_legend_handle(rect, label, index=i)\r\n",
      "\r\n",
      "    def _post_plot_logic(self, ax, data):\r\n",
      "        if self.use_index:\r\n",
      "            str_index = [pprint_thing(key) for key in data.index]\r\n",
      "        else:\r\n",
      "            str_index = [pprint_thing(key) for key in range(data.shape[0])]\r\n",
      "        name = self._get_index_name()\r\n",
      "\r\n",
      "        s_edge = self.ax_pos[0] - 0.25 + self.lim_offset\r\n",
      "        e_edge = self.ax_pos[-1] + 0.25 + self.bar_width + self.lim_offset\r\n",
      "\r\n",
      "        self._decorate_ticks(ax, name, str_index, s_edge, e_edge)\r\n",
      "\r\n",
      "    def _decorate_ticks(self, ax, name, ticklabels, start_edge, end_edge):\r\n",
      "        ax.set_xlim((start_edge, end_edge))\r\n",
      "        ax.set_xticks(self.tick_pos)\r\n",
      "        ax.set_xticklabels(ticklabels)\r\n",
      "        if name is not None and self.use_index:\r\n",
      "            ax.set_xlabel(name)\r\n",
      "\r\n",
      "\r\n",
      "class BarhPlot(BarPlot):\r\n",
      "    _kind = 'barh'\r\n",
      "    _default_rot = 0\r\n",
      "    orientation = 'horizontal'\r\n",
      "\r\n",
      "    @property\r\n",
      "    def _start_base(self):\r\n",
      "        return self.left\r\n",
      "\r\n",
      "    @classmethod\r\n",
      "    def _plot(cls, ax, x, y, w, start=0, log=False, **kwds):\r\n",
      "        return ax.barh(x, y, w, left=start, log=log, **kwds)\r\n",
      "\r\n",
      "    def _decorate_ticks(self, ax, name, ticklabels, start_edge, end_edge):\r\n",
      "        # horizontal bars\r\n",
      "        ax.set_ylim((start_edge, end_edge))\r\n",
      "        ax.set_yticks(self.tick_pos)\r\n",
      "        ax.set_yticklabels(ticklabels)\r\n",
      "        if name is not None and self.use_index:\r\n",
      "            ax.set_ylabel(name)\r\n",
      "\r\n",
      "\r\n",
      "class HistPlot(LinePlot):\r\n",
      "    _kind = 'hist'\r\n",
      "\r\n",
      "    def __init__(self, data, bins=10, bottom=0, **kwargs):\r\n",
      "        self.bins = bins        # use mpl default\r\n",
      "        self.bottom = bottom\r\n",
      "        # Do not call LinePlot.__init__ which may fill nan\r\n",
      "        MPLPlot.__init__(self, data, **kwargs)\r\n",
      "\r\n",
      "    def _args_adjust(self):\r\n",
      "        if is_integer(self.bins):\r\n",
      "            # create common bin edge\r\n",
      "            values = (self.data._convert(datetime=True)._get_numeric_data())\r\n",
      "            values = np.ravel(values)\r\n",
      "            values = values[~isna(values)]\r\n",
      "\r\n",
      "            hist, self.bins = np.histogram(\r\n",
      "                values, bins=self.bins,\r\n",
      "                range=self.kwds.get('range', None),\r\n",
      "                weights=self.kwds.get('weights', None))\r\n",
      "\r\n",
      "        if is_list_like(self.bottom):\r\n",
      "            self.bottom = np.array(self.bottom)\r\n",
      "\r\n",
      "    @classmethod\r\n",
      "    def _plot(cls, ax, y, style=None, bins=None, bottom=0, column_num=0,\r\n",
      "              stacking_id=None, **kwds):\r\n",
      "        if column_num == 0:\r\n",
      "            cls._initialize_stacker(ax, stacking_id, len(bins) - 1)\r\n",
      "        y = y[~isna(y)]\r\n",
      "\r\n",
      "        base = np.zeros(len(bins) - 1)\r\n",
      "        bottom = bottom + \\\r\n",
      "            cls._get_stacked_values(ax, stacking_id, base, kwds['label'])\r\n",
      "        # ignore style\r\n",
      "        n, bins, patches = ax.hist(y, bins=bins, bottom=bottom, **kwds)\r\n",
      "        cls._update_stacker(ax, stacking_id, n)\r\n",
      "        return patches\r\n",
      "\r\n",
      "    def _make_plot(self):\r\n",
      "        colors = self._get_colors()\r\n",
      "        stacking_id = self._get_stacking_id()\r\n",
      "\r\n",
      "        for i, (label, y) in enumerate(self._iter_data()):\r\n",
      "            ax = self._get_ax(i)\r\n",
      "\r\n",
      "            kwds = self.kwds.copy()\r\n",
      "\r\n",
      "            label = pprint_thing(label)\r\n",
      "            kwds['label'] = label\r\n",
      "\r\n",
      "            style, kwds = self._apply_style_colors(colors, kwds, i, label)\r\n",
      "            if style is not None:\r\n",
      "                kwds['style'] = style\r\n",
      "\r\n",
      "            kwds = self._make_plot_keywords(kwds, y)\r\n",
      "            artists = self._plot(ax, y, column_num=i,\r\n",
      "                                 stacking_id=stacking_id, **kwds)\r\n",
      "            self._add_legend_handle(artists[0], label, index=i)\r\n",
      "\r\n",
      "    def _make_plot_keywords(self, kwds, y):\r\n",
      "        \"\"\"merge BoxPlot/KdePlot properties to passed kwds\"\"\"\r\n",
      "        # y is required for KdePlot\r\n",
      "        kwds['bottom'] = self.bottom\r\n",
      "        kwds['bins'] = self.bins\r\n",
      "        return kwds\r\n",
      "\r\n",
      "    def _post_plot_logic(self, ax, data):\r\n",
      "        if self.orientation == 'horizontal':\r\n",
      "            ax.set_xlabel('Frequency')\r\n",
      "        else:\r\n",
      "            ax.set_ylabel('Frequency')\r\n",
      "\r\n",
      "    @property\r\n",
      "    def orientation(self):\r\n",
      "        if self.kwds.get('orientation', None) == 'horizontal':\r\n",
      "            return 'horizontal'\r\n",
      "        else:\r\n",
      "            return 'vertical'\r\n",
      "\r\n",
      "\r\n",
      "class KdePlot(HistPlot):\r\n",
      "    _kind = 'kde'\r\n",
      "    orientation = 'vertical'\r\n",
      "\r\n",
      "    def __init__(self, data, bw_method=None, ind=None, **kwargs):\r\n",
      "        MPLPlot.__init__(self, data, **kwargs)\r\n",
      "        self.bw_method = bw_method\r\n",
      "        self.ind = ind\r\n",
      "\r\n",
      "    def _args_adjust(self):\r\n",
      "        pass\r\n",
      "\r\n",
      "    def _get_ind(self, y):\r\n",
      "        if self.ind is None:\r\n",
      "            # np.nanmax() and np.nanmin() ignores the missing values\r\n",
      "            sample_range = np.nanmax(y) - np.nanmin(y)\r\n",
      "            ind = np.linspace(np.nanmin(y) - 0.5 * sample_range,\r\n",
      "                              np.nanmax(y) + 0.5 * sample_range, 1000)\r\n",
      "        else:\r\n",
      "            ind = self.ind\r\n",
      "        return ind\r\n",
      "\r\n",
      "    @classmethod\r\n",
      "    def _plot(cls, ax, y, style=None, bw_method=None, ind=None,\r\n",
      "              column_num=None, stacking_id=None, **kwds):\r\n",
      "        from scipy.stats import gaussian_kde\r\n",
      "        from scipy import __version__ as spv\r\n",
      "\r\n",
      "        y = remove_na_arraylike(y)\r\n",
      "\r\n",
      "        if LooseVersion(spv) >= '0.11.0':\r\n",
      "            gkde = gaussian_kde(y, bw_method=bw_method)\r\n",
      "        else:\r\n",
      "            gkde = gaussian_kde(y)\r\n",
      "            if bw_method is not None:\r\n",
      "                msg = ('bw_method was added in Scipy 0.11.0.' +\r\n",
      "                       ' Scipy version in use is %s.' % spv)\r\n",
      "                warnings.warn(msg)\r\n",
      "\r\n",
      "        y = gkde.evaluate(ind)\r\n",
      "        lines = MPLPlot._plot(ax, ind, y, style=style, **kwds)\r\n",
      "        return lines\r\n",
      "\r\n",
      "    def _make_plot_keywords(self, kwds, y):\r\n",
      "        kwds['bw_method'] = self.bw_method\r\n",
      "        kwds['ind'] = self._get_ind(y)\r\n",
      "        return kwds\r\n",
      "\r\n",
      "    def _post_plot_logic(self, ax, data):\r\n",
      "        ax.set_ylabel('Density')\r\n",
      "\r\n",
      "\r\n",
      "class PiePlot(MPLPlot):\r\n",
      "    _kind = 'pie'\r\n",
      "    _layout_type = 'horizontal'\r\n",
      "\r\n",
      "    def __init__(self, data, kind=None, **kwargs):\r\n",
      "        data = data.fillna(value=0)\r\n",
      "        if (data < 0).any().any():\r\n",
      "            raise ValueError(\"{0} doesn't allow negative values\".format(kind))\r\n",
      "        MPLPlot.__init__(self, data, kind=kind, **kwargs)\r\n",
      "\r\n",
      "    def _args_adjust(self):\r\n",
      "        self.grid = False\r\n",
      "        self.logy = False\r\n",
      "        self.logx = False\r\n",
      "        self.loglog = False\r\n",
      "\r\n",
      "    def _validate_color_args(self):\r\n",
      "        pass\r\n",
      "\r\n",
      "    def _make_plot(self):\r\n",
      "        colors = self._get_colors(\r\n",
      "            num_colors=len(self.data), color_kwds='colors')\r\n",
      "        self.kwds.setdefault('colors', colors)\r\n",
      "\r\n",
      "        for i, (label, y) in enumerate(self._iter_data()):\r\n",
      "            ax = self._get_ax(i)\r\n",
      "            if label is not None:\r\n",
      "                label = pprint_thing(label)\r\n",
      "                ax.set_ylabel(label)\r\n",
      "\r\n",
      "            kwds = self.kwds.copy()\r\n",
      "\r\n",
      "            def blank_labeler(label, value):\r\n",
      "                if value == 0:\r\n",
      "                    return ''\r\n",
      "                else:\r\n",
      "                    return label\r\n",
      "\r\n",
      "            idx = [pprint_thing(v) for v in self.data.index]\r\n",
      "            labels = kwds.pop('labels', idx)\r\n",
      "            # labels is used for each wedge's labels\r\n",
      "            # Blank out labels for values of 0 so they don't overlap\r\n",
      "            # with nonzero wedges\r\n",
      "            if labels is not None:\r\n",
      "                blabels = [blank_labeler(l, value) for\r\n",
      "                           l, value in zip(labels, y)]\r\n",
      "            else:\r\n",
      "                blabels = None\r\n",
      "            results = ax.pie(y, labels=blabels, **kwds)\r\n",
      "\r\n",
      "            if kwds.get('autopct', None) is not None:\r\n",
      "                patches, texts, autotexts = results\r\n",
      "            else:\r\n",
      "                patches, texts = results\r\n",
      "                autotexts = []\r\n",
      "\r\n",
      "            if self.fontsize is not None:\r\n",
      "                for t in texts + autotexts:\r\n",
      "                    t.set_fontsize(self.fontsize)\r\n",
      "\r\n",
      "            # leglabels is used for legend labels\r\n",
      "            leglabels = labels if labels is not None else idx\r\n",
      "            for p, l in zip(patches, leglabels):\r\n",
      "                self._add_legend_handle(p, l)\r\n",
      "\r\n",
      "\r\n",
      "class BoxPlot(LinePlot):\r\n",
      "    _kind = 'box'\r\n",
      "    _layout_type = 'horizontal'\r\n",
      "\r\n",
      "    _valid_return_types = (None, 'axes', 'dict', 'both')\r\n",
      "    # namedtuple to hold results\r\n",
      "    BP = namedtuple(\"Boxplot\", ['ax', 'lines'])\r\n",
      "\r\n",
      "    def __init__(self, data, return_type='axes', **kwargs):\r\n",
      "        # Do not call LinePlot.__init__ which may fill nan\r\n",
      "        if return_type not in self._valid_return_types:\r\n",
      "            raise ValueError(\r\n",
      "                \"return_type must be {None, 'axes', 'dict', 'both'}\")\r\n",
      "\r\n",
      "        self.return_type = return_type\r\n",
      "        MPLPlot.__init__(self, data, **kwargs)\r\n",
      "\r\n",
      "    def _args_adjust(self):\r\n",
      "        if self.subplots:\r\n",
      "            # Disable label ax sharing. Otherwise, all subplots shows last\r\n",
      "            # column label\r\n",
      "            if self.orientation == 'vertical':\r\n",
      "                self.sharex = False\r\n",
      "            else:\r\n",
      "                self.sharey = False\r\n",
      "\r\n",
      "    @classmethod\r\n",
      "    def _plot(cls, ax, y, column_num=None, return_type='axes', **kwds):\r\n",
      "        if y.ndim == 2:\r\n",
      "            y = [remove_na_arraylike(v) for v in y]\r\n",
      "            # Boxplot fails with empty arrays, so need to add a NaN\r\n",
      "            #   if any cols are empty\r\n",
      "            # GH 8181\r\n",
      "            y = [v if v.size > 0 else np.array([np.nan]) for v in y]\r\n",
      "        else:\r\n",
      "            y = remove_na_arraylike(y)\r\n",
      "        bp = ax.boxplot(y, **kwds)\r\n",
      "\r\n",
      "        if return_type == 'dict':\r\n",
      "            return bp, bp\r\n",
      "        elif return_type == 'both':\r\n",
      "            return cls.BP(ax=ax, lines=bp), bp\r\n",
      "        else:\r\n",
      "            return ax, bp\r\n",
      "\r\n",
      "    def _validate_color_args(self):\r\n",
      "        if 'color' in self.kwds:\r\n",
      "            if self.colormap is not None:\r\n",
      "                warnings.warn(\"'color' and 'colormap' cannot be used \"\r\n",
      "                              \"simultaneously. Using 'color'\")\r\n",
      "            self.color = self.kwds.pop('color')\r\n",
      "\r\n",
      "            if isinstance(self.color, dict):\r\n",
      "                valid_keys = ['boxes', 'whiskers', 'medians', 'caps']\r\n",
      "                for key, values in compat.iteritems(self.color):\r\n",
      "                    if key not in valid_keys:\r\n",
      "                        raise ValueError(\"color dict contains invalid \"\r\n",
      "                                         \"key '{0}' \"\r\n",
      "                                         \"The key must be either {1}\"\r\n",
      "                                         .format(key, valid_keys))\r\n",
      "        else:\r\n",
      "            self.color = None\r\n",
      "\r\n",
      "        # get standard colors for default\r\n",
      "        colors = _get_standard_colors(num_colors=3,\r\n",
      "                                      colormap=self.colormap,\r\n",
      "                                      color=None)\r\n",
      "        # use 2 colors by default, for box/whisker and median\r\n",
      "        # flier colors isn't needed here\r\n",
      "        # because it can be specified by ``sym`` kw\r\n",
      "        self._boxes_c = colors[0]\r\n",
      "        self._whiskers_c = colors[0]\r\n",
      "        self._medians_c = colors[2]\r\n",
      "        self._caps_c = 'k'          # mpl default\r\n",
      "\r\n",
      "    def _get_colors(self, num_colors=None, color_kwds='color'):\r\n",
      "        pass\r\n",
      "\r\n",
      "    def maybe_color_bp(self, bp):\r\n",
      "        if isinstance(self.color, dict):\r\n",
      "            boxes = self.color.get('boxes', self._boxes_c)\r\n",
      "            whiskers = self.color.get('whiskers', self._whiskers_c)\r\n",
      "            medians = self.color.get('medians', self._medians_c)\r\n",
      "            caps = self.color.get('caps', self._caps_c)\r\n",
      "        else:\r\n",
      "            # Other types are forwarded to matplotlib\r\n",
      "            # If None, use default colors\r\n",
      "            boxes = self.color or self._boxes_c\r\n",
      "            whiskers = self.color or self._whiskers_c\r\n",
      "            medians = self.color or self._medians_c\r\n",
      "            caps = self.color or self._caps_c\r\n",
      "\r\n",
      "        from matplotlib.artist import setp\r\n",
      "        setp(bp['boxes'], color=boxes, alpha=1)\r\n",
      "        setp(bp['whiskers'], color=whiskers, alpha=1)\r\n",
      "        setp(bp['medians'], color=medians, alpha=1)\r\n",
      "        setp(bp['caps'], color=caps, alpha=1)\r\n",
      "\r\n",
      "    def _make_plot(self):\r\n",
      "        if self.subplots:\r\n",
      "            from pandas.core.series import Series\r\n",
      "            self._return_obj = Series()\r\n",
      "\r\n",
      "            for i, (label, y) in enumerate(self._iter_data()):\r\n",
      "                ax = self._get_ax(i)\r\n",
      "                kwds = self.kwds.copy()\r\n",
      "\r\n",
      "                ret, bp = self._plot(ax, y, column_num=i,\r\n",
      "                                     return_type=self.return_type, **kwds)\r\n",
      "                self.maybe_color_bp(bp)\r\n",
      "                self._return_obj[label] = ret\r\n",
      "\r\n",
      "                label = [pprint_thing(label)]\r\n",
      "                self._set_ticklabels(ax, label)\r\n",
      "        else:\r\n",
      "            y = self.data.values.T\r\n",
      "            ax = self._get_ax(0)\r\n",
      "            kwds = self.kwds.copy()\r\n",
      "\r\n",
      "            ret, bp = self._plot(ax, y, column_num=0,\r\n",
      "                                 return_type=self.return_type, **kwds)\r\n",
      "            self.maybe_color_bp(bp)\r\n",
      "            self._return_obj = ret\r\n",
      "\r\n",
      "            labels = [l for l, _ in self._iter_data()]\r\n",
      "            labels = [pprint_thing(l) for l in labels]\r\n",
      "            if not self.use_index:\r\n",
      "                labels = [pprint_thing(key) for key in range(len(labels))]\r\n",
      "            self._set_ticklabels(ax, labels)\r\n",
      "\r\n",
      "    def _set_ticklabels(self, ax, labels):\r\n",
      "        if self.orientation == 'vertical':\r\n",
      "            ax.set_xticklabels(labels)\r\n",
      "        else:\r\n",
      "            ax.set_yticklabels(labels)\r\n",
      "\r\n",
      "    def _make_legend(self):\r\n",
      "        pass\r\n",
      "\r\n",
      "    def _post_plot_logic(self, ax, data):\r\n",
      "        pass\r\n",
      "\r\n",
      "    @property\r\n",
      "    def orientation(self):\r\n",
      "        if self.kwds.get('vert', True):\r\n",
      "            return 'vertical'\r\n",
      "        else:\r\n",
      "            return 'horizontal'\r\n",
      "\r\n",
      "    @property\r\n",
      "    def result(self):\r\n",
      "        if self.return_type is None:\r\n",
      "            return super(BoxPlot, self).result\r\n",
      "        else:\r\n",
      "            return self._return_obj\r\n",
      "\r\n",
      "\r\n",
      "# kinds supported by both dataframe and series\r\n",
      "_common_kinds = ['line', 'bar', 'barh',\r\n",
      "                 'kde', 'density', 'area', 'hist', 'box']\r\n",
      "# kinds supported by dataframe\r\n",
      "_dataframe_kinds = ['scatter', 'hexbin']\r\n",
      "# kinds supported only by series or dataframe single column\r\n",
      "_series_kinds = ['pie']\r\n",
      "_all_kinds = _common_kinds + _dataframe_kinds + _series_kinds\r\n",
      "\r\n",
      "_klasses = [LinePlot, BarPlot, BarhPlot, KdePlot, HistPlot, BoxPlot,\r\n",
      "            ScatterPlot, HexBinPlot, AreaPlot, PiePlot]\r\n",
      "\r\n",
      "_plot_klass = {}\r\n",
      "for klass in _klasses:\r\n",
      "    _plot_klass[klass._kind] = klass\r\n",
      "\r\n",
      "\r\n",
      "def _plot(data, x=None, y=None, subplots=False,\r\n",
      "          ax=None, kind='line', **kwds):\r\n",
      "    kind = _get_standard_kind(kind.lower().strip())\r\n",
      "    if kind in _all_kinds:\r\n",
      "        klass = _plot_klass[kind]\r\n",
      "    else:\r\n",
      "        raise ValueError(\"%r is not a valid plot kind\" % kind)\r\n",
      "\r\n",
      "    from pandas import DataFrame\r\n",
      "    if kind in _dataframe_kinds:\r\n",
      "        if isinstance(data, DataFrame):\r\n",
      "            plot_obj = klass(data, x=x, y=y, subplots=subplots, ax=ax,\r\n",
      "                             kind=kind, **kwds)\r\n",
      "        else:\r\n",
      "            raise ValueError(\"plot kind %r can only be used for data frames\"\r\n",
      "                             % kind)\r\n",
      "\r\n",
      "    elif kind in _series_kinds:\r\n",
      "        if isinstance(data, DataFrame):\r\n",
      "            if y is None and subplots is False:\r\n",
      "                msg = \"{0} requires either y column or 'subplots=True'\"\r\n",
      "                raise ValueError(msg.format(kind))\r\n",
      "            elif y is not None:\r\n",
      "                if is_integer(y) and not data.columns.holds_integer():\r\n",
      "                    y = data.columns[y]\r\n",
      "                # converted to series actually. copy to not modify\r\n",
      "                data = data[y].copy()\r\n",
      "                data.index.name = y\r\n",
      "        plot_obj = klass(data, subplots=subplots, ax=ax, kind=kind, **kwds)\r\n",
      "    else:\r\n",
      "        if isinstance(data, DataFrame):\r\n",
      "            if x is not None:\r\n",
      "                if is_integer(x) and not data.columns.holds_integer():\r\n",
      "                    x = data.columns[x]\r\n",
      "                data = data.set_index(x)\r\n",
      "\r\n",
      "            if y is not None:\r\n",
      "                if is_integer(y) and not data.columns.holds_integer():\r\n",
      "                    y = data.columns[y]\r\n",
      "                label = kwds['label'] if 'label' in kwds else y\r\n",
      "                series = data[y].copy()  # Don't modify\r\n",
      "                series.name = label\r\n",
      "\r\n",
      "                for kw in ['xerr', 'yerr']:\r\n",
      "                    if (kw in kwds) and \\\r\n",
      "                        (isinstance(kwds[kw], string_types) or\r\n",
      "                            is_integer(kwds[kw])):\r\n",
      "                        try:\r\n",
      "                            kwds[kw] = data[kwds[kw]]\r\n",
      "                        except (IndexError, KeyError, TypeError):\r\n",
      "                            pass\r\n",
      "                data = series\r\n",
      "        plot_obj = klass(data, subplots=subplots, ax=ax, kind=kind, **kwds)\r\n",
      "\r\n",
      "    plot_obj.generate()\r\n",
      "    plot_obj.draw()\r\n",
      "    return plot_obj.result\r\n",
      "\r\n",
      "\r\n",
      "df_kind = \"\"\"- 'scatter' : scatter plot\r\n",
      "        - 'hexbin' : hexbin plot\"\"\"\r\n",
      "series_kind = \"\"\r\n",
      "\r\n",
      "df_coord = \"\"\"x : label or position, default None\r\n",
      "    y : label or position, default None\r\n",
      "        Allows plotting of one column versus another\"\"\"\r\n",
      "series_coord = \"\"\r\n",
      "\r\n",
      "df_unique = \"\"\"stacked : boolean, default False in line and\r\n",
      "        bar plots, and True in area plot. If True, create stacked plot.\r\n",
      "    sort_columns : boolean, default False\r\n",
      "        Sort column names to determine plot ordering\r\n",
      "    secondary_y : boolean or sequence, default False\r\n",
      "        Whether to plot on the secondary y-axis\r\n",
      "        If a list/tuple, which columns to plot on secondary y-axis\"\"\"\r\n",
      "series_unique = \"\"\"label : label argument to provide to plot\r\n",
      "    secondary_y : boolean or sequence of ints, default False\r\n",
      "        If True then y-axis will be on the right\"\"\"\r\n",
      "\r\n",
      "df_ax = \"\"\"ax : matplotlib axes object, default None\r\n",
      "    subplots : boolean, default False\r\n",
      "        Make separate subplots for each column\r\n",
      "    sharex : boolean, default True if ax is None else False\r\n",
      "        In case subplots=True, share x axis and set some x axis labels to\r\n",
      "        invisible; defaults to True if ax is None otherwise False if an ax\r\n",
      "        is passed in; Be aware, that passing in both an ax and sharex=True\r\n",
      "        will alter all x axis labels for all axis in a figure!\r\n",
      "    sharey : boolean, default False\r\n",
      "        In case subplots=True, share y axis and set some y axis labels to\r\n",
      "        invisible\r\n",
      "    layout : tuple (optional)\r\n",
      "        (rows, columns) for the layout of subplots\"\"\"\r\n",
      "series_ax = \"\"\"ax : matplotlib axes object\r\n",
      "        If not passed, uses gca()\"\"\"\r\n",
      "\r\n",
      "df_note = \"\"\"- If `kind` = 'scatter' and the argument `c` is the name of a dataframe\r\n",
      "      column, the values of that column are used to color each point.\r\n",
      "    - If `kind` = 'hexbin', you can control the size of the bins with the\r\n",
      "      `gridsize` argument. By default, a histogram of the counts around each\r\n",
      "      `(x, y)` point is computed. You can specify alternative aggregations\r\n",
      "      by passing values to the `C` and `reduce_C_function` arguments.\r\n",
      "      `C` specifies the value at each `(x, y)` point and `reduce_C_function`\r\n",
      "      is a function of one argument that reduces all the values in a bin to\r\n",
      "      a single number (e.g. `mean`, `max`, `sum`, `std`).\"\"\"\r\n",
      "series_note = \"\"\r\n",
      "\r\n",
      "_shared_doc_df_kwargs = dict(klass='DataFrame', klass_obj='df',\r\n",
      "                             klass_kind=df_kind, klass_coord=df_coord,\r\n",
      "                             klass_ax=df_ax, klass_unique=df_unique,\r\n",
      "                             klass_note=df_note)\r\n",
      "_shared_doc_series_kwargs = dict(klass='Series', klass_obj='s',\r\n",
      "                                 klass_kind=series_kind,\r\n",
      "                                 klass_coord=series_coord, klass_ax=series_ax,\r\n",
      "                                 klass_unique=series_unique,\r\n",
      "                                 klass_note=series_note)\r\n",
      "\r\n",
      "_shared_docs['plot'] = \"\"\"\r\n",
      "    Make plots of %(klass)s using matplotlib / pylab.\r\n",
      "\r\n",
      "    *New in version 0.17.0:* Each plot kind has a corresponding method on the\r\n",
      "    ``%(klass)s.plot`` accessor:\r\n",
      "    ``%(klass_obj)s.plot(kind='line')`` is equivalent to\r\n",
      "    ``%(klass_obj)s.plot.line()``.\r\n",
      "\r\n",
      "    Parameters\r\n",
      "    ----------\r\n",
      "    data : %(klass)s\r\n",
      "    %(klass_coord)s\r\n",
      "    kind : str\r\n",
      "        - 'line' : line plot (default)\r\n",
      "        - 'bar' : vertical bar plot\r\n",
      "        - 'barh' : horizontal bar plot\r\n",
      "        - 'hist' : histogram\r\n",
      "        - 'box' : boxplot\r\n",
      "        - 'kde' : Kernel Density Estimation plot\r\n",
      "        - 'density' : same as 'kde'\r\n",
      "        - 'area' : area plot\r\n",
      "        - 'pie' : pie plot\r\n",
      "        %(klass_kind)s\r\n",
      "    %(klass_ax)s\r\n",
      "    figsize : a tuple (width, height) in inches\r\n",
      "    use_index : boolean, default True\r\n",
      "        Use index as ticks for x axis\r\n",
      "    title : string or list\r\n",
      "        Title to use for the plot. If a string is passed, print the string at\r\n",
      "        the top of the figure. If a list is passed and `subplots` is True,\r\n",
      "        print each item in the list above the corresponding subplot.\r\n",
      "    grid : boolean, default None (matlab style default)\r\n",
      "        Axis grid lines\r\n",
      "    legend : False/True/'reverse'\r\n",
      "        Place legend on axis subplots\r\n",
      "    style : list or dict\r\n",
      "        matplotlib line style per column\r\n",
      "    logx : boolean, default False\r\n",
      "        Use log scaling on x axis\r\n",
      "    logy : boolean, default False\r\n",
      "        Use log scaling on y axis\r\n",
      "    loglog : boolean, default False\r\n",
      "        Use log scaling on both x and y axes\r\n",
      "    xticks : sequence\r\n",
      "        Values to use for the xticks\r\n",
      "    yticks : sequence\r\n",
      "        Values to use for the yticks\r\n",
      "    xlim : 2-tuple/list\r\n",
      "    ylim : 2-tuple/list\r\n",
      "    rot : int, default None\r\n",
      "        Rotation for ticks (xticks for vertical, yticks for horizontal plots)\r\n",
      "    fontsize : int, default None\r\n",
      "        Font size for xticks and yticks\r\n",
      "    colormap : str or matplotlib colormap object, default None\r\n",
      "        Colormap to select colors from. If string, load colormap with that name\r\n",
      "        from matplotlib.\r\n",
      "    colorbar : boolean, optional\r\n",
      "        If True, plot colorbar (only relevant for 'scatter' and 'hexbin' plots)\r\n",
      "    position : float\r\n",
      "        Specify relative alignments for bar plot layout.\r\n",
      "        From 0 (left/bottom-end) to 1 (right/top-end). Default is 0.5 (center)\r\n",
      "    table : boolean, Series or DataFrame, default False\r\n",
      "        If True, draw a table using the data in the DataFrame and the data will\r\n",
      "        be transposed to meet matplotlib's default layout.\r\n",
      "        If a Series or DataFrame is passed, use passed data to draw a table.\r\n",
      "    yerr : DataFrame, Series, array-like, dict and str\r\n",
      "        See :ref:`Plotting with Error Bars <visualization.errorbars>` for\r\n",
      "        detail.\r\n",
      "    xerr : same types as yerr.\r\n",
      "    %(klass_unique)s\r\n",
      "    mark_right : boolean, default True\r\n",
      "        When using a secondary_y axis, automatically mark the column\r\n",
      "        labels with \"(right)\" in the legend\r\n",
      "    kwds : keywords\r\n",
      "        Options to pass to matplotlib plotting method\r\n",
      "\r\n",
      "    Returns\r\n",
      "    -------\r\n",
      "    axes : matplotlib.AxesSubplot or np.array of them\r\n",
      "\r\n",
      "    Notes\r\n",
      "    -----\r\n",
      "\r\n",
      "    - See matplotlib documentation online for more on this subject\r\n",
      "    - If `kind` = 'bar' or 'barh', you can specify relative alignments\r\n",
      "      for bar plot layout by `position` keyword.\r\n",
      "      From 0 (left/bottom-end) to 1 (right/top-end). Default is 0.5 (center)\r\n",
      "    %(klass_note)s\r\n",
      "\r\n",
      "    \"\"\"\r\n",
      "\r\n",
      "\r\n",
      "@Appender(_shared_docs['plot'] % _shared_doc_df_kwargs)\r\n",
      "def plot_frame(data, x=None, y=None, kind='line', ax=None,\r\n",
      "               subplots=False, sharex=None, sharey=False, layout=None,\r\n",
      "               figsize=None, use_index=True, title=None, grid=None,\r\n",
      "               legend=True, style=None, logx=False, logy=False, loglog=False,\r\n",
      "               xticks=None, yticks=None, xlim=None, ylim=None,\r\n",
      "               rot=None, fontsize=None, colormap=None, table=False,\r\n",
      "               yerr=None, xerr=None,\r\n",
      "               secondary_y=False, sort_columns=False,\r\n",
      "               **kwds):\r\n",
      "    return _plot(data, kind=kind, x=x, y=y, ax=ax,\r\n",
      "                 subplots=subplots, sharex=sharex, sharey=sharey,\r\n",
      "                 layout=layout, figsize=figsize, use_index=use_index,\r\n",
      "                 title=title, grid=grid, legend=legend,\r\n",
      "                 style=style, logx=logx, logy=logy, loglog=loglog,\r\n",
      "                 xticks=xticks, yticks=yticks, xlim=xlim, ylim=ylim,\r\n",
      "                 rot=rot, fontsize=fontsize, colormap=colormap, table=table,\r\n",
      "                 yerr=yerr, xerr=xerr,\r\n",
      "                 secondary_y=secondary_y, sort_columns=sort_columns,\r\n",
      "                 **kwds)\r\n",
      "\r\n",
      "\r\n",
      "@Appender(_shared_docs['plot'] % _shared_doc_series_kwargs)\r\n",
      "def plot_series(data, kind='line', ax=None,                    # Series unique\r\n",
      "                figsize=None, use_index=True, title=None, grid=None,\r\n",
      "                legend=False, style=None, logx=False, logy=False, loglog=False,\r\n",
      "                xticks=None, yticks=None, xlim=None, ylim=None,\r\n",
      "                rot=None, fontsize=None, colormap=None, table=False,\r\n",
      "                yerr=None, xerr=None,\r\n",
      "                label=None, secondary_y=False,                 # Series unique\r\n",
      "                **kwds):\r\n",
      "\r\n",
      "    import matplotlib.pyplot as plt\r\n",
      "    if ax is None and len(plt.get_fignums()) > 0:\r\n",
      "        ax = _gca()\r\n",
      "        ax = MPLPlot._get_ax_layer(ax)\r\n",
      "    return _plot(data, kind=kind, ax=ax,\r\n",
      "                 figsize=figsize, use_index=use_index, title=title,\r\n",
      "                 grid=grid, legend=legend,\r\n",
      "                 style=style, logx=logx, logy=logy, loglog=loglog,\r\n",
      "                 xticks=xticks, yticks=yticks, xlim=xlim, ylim=ylim,\r\n",
      "                 rot=rot, fontsize=fontsize, colormap=colormap, table=table,\r\n",
      "                 yerr=yerr, xerr=xerr,\r\n",
      "                 label=label, secondary_y=secondary_y,\r\n",
      "                 **kwds)\r\n",
      "\r\n",
      "\r\n",
      "_shared_docs['boxplot'] = \"\"\"\r\n",
      "    Make a box plot from DataFrame column optionally grouped by some columns or\r\n",
      "    other inputs\r\n",
      "\r\n",
      "    Parameters\r\n",
      "    ----------\r\n",
      "    data : the pandas object holding the data\r\n",
      "    column : column name or list of names, or vector\r\n",
      "        Can be any valid input to groupby\r\n",
      "    by : string or sequence\r\n",
      "        Column in the DataFrame to group by\r\n",
      "    ax : Matplotlib axes object, optional\r\n",
      "    fontsize : int or string\r\n",
      "    rot : label rotation angle\r\n",
      "    figsize : A tuple (width, height) in inches\r\n",
      "    grid : Setting this to True will show the grid\r\n",
      "    layout : tuple (optional)\r\n",
      "        (rows, columns) for the layout of the plot\r\n",
      "    return_type : {None, 'axes', 'dict', 'both'}, default None\r\n",
      "        The kind of object to return. The default is ``axes``\r\n",
      "        'axes' returns the matplotlib axes the boxplot is drawn on;\r\n",
      "        'dict' returns a dictionary  whose values are the matplotlib\r\n",
      "        Lines of the boxplot;\r\n",
      "        'both' returns a namedtuple with the axes and dict.\r\n",
      "\r\n",
      "        When grouping with ``by``, a Series mapping columns to ``return_type``\r\n",
      "        is returned, unless ``return_type`` is None, in which case a NumPy\r\n",
      "        array of axes is returned with the same shape as ``layout``.\r\n",
      "        See the prose documentation for more.\r\n",
      "\r\n",
      "    kwds : other plotting keyword arguments to be passed to matplotlib boxplot\r\n",
      "           function\r\n",
      "\r\n",
      "    Returns\r\n",
      "    -------\r\n",
      "    lines : dict\r\n",
      "    ax : matplotlib Axes\r\n",
      "    (ax, lines): namedtuple\r\n",
      "\r\n",
      "    Notes\r\n",
      "    -----\r\n",
      "    Use ``return_type='dict'`` when you want to tweak the appearance\r\n",
      "    of the lines after plotting. In this case a dict containing the Lines\r\n",
      "    making up the boxes, caps, fliers, medians, and whiskers is returned.\r\n",
      "    \"\"\"\r\n",
      "\r\n",
      "\r\n",
      "@Appender(_shared_docs['boxplot'] % _shared_doc_kwargs)\r\n",
      "def boxplot(data, column=None, by=None, ax=None, fontsize=None,\r\n",
      "            rot=0, grid=True, figsize=None, layout=None, return_type=None,\r\n",
      "            **kwds):\r\n",
      "\r\n",
      "    # validate return_type:\r\n",
      "    if return_type not in BoxPlot._valid_return_types:\r\n",
      "        raise ValueError(\"return_type must be {'axes', 'dict', 'both'}\")\r\n",
      "\r\n",
      "    from pandas import Series, DataFrame\r\n",
      "    if isinstance(data, Series):\r\n",
      "        data = DataFrame({'x': data})\r\n",
      "        column = 'x'\r\n",
      "\r\n",
      "    def _get_colors():\r\n",
      "        return _get_standard_colors(color=kwds.get('color'), num_colors=1)\r\n",
      "\r\n",
      "    def maybe_color_bp(bp):\r\n",
      "        if 'color' not in kwds:\r\n",
      "            from matplotlib.artist import setp\r\n",
      "            setp(bp['boxes'], color=colors[0], alpha=1)\r\n",
      "            setp(bp['whiskers'], color=colors[0], alpha=1)\r\n",
      "            setp(bp['medians'], color=colors[2], alpha=1)\r\n",
      "\r\n",
      "    def plot_group(keys, values, ax):\r\n",
      "        keys = [pprint_thing(x) for x in keys]\r\n",
      "        values = [np.asarray(remove_na_arraylike(v)) for v in values]\r\n",
      "        bp = ax.boxplot(values, **kwds)\r\n",
      "        if fontsize is not None:\r\n",
      "            ax.tick_params(axis='both', labelsize=fontsize)\r\n",
      "        if kwds.get('vert', 1):\r\n",
      "            ax.set_xticklabels(keys, rotation=rot)\r\n",
      "        else:\r\n",
      "            ax.set_yticklabels(keys, rotation=rot)\r\n",
      "        maybe_color_bp(bp)\r\n",
      "\r\n",
      "        # Return axes in multiplot case, maybe revisit later # 985\r\n",
      "        if return_type == 'dict':\r\n",
      "            return bp\r\n",
      "        elif return_type == 'both':\r\n",
      "            return BoxPlot.BP(ax=ax, lines=bp)\r\n",
      "        else:\r\n",
      "            return ax\r\n",
      "\r\n",
      "    colors = _get_colors()\r\n",
      "    if column is None:\r\n",
      "        columns = None\r\n",
      "    else:\r\n",
      "        if isinstance(column, (list, tuple)):\r\n",
      "            columns = column\r\n",
      "        else:\r\n",
      "            columns = [column]\r\n",
      "\r\n",
      "    if by is not None:\r\n",
      "        # Prefer array return type for 2-D plots to match the subplot layout\r\n",
      "        # https://github.com/pandas-dev/pandas/pull/12216#issuecomment-241175580\r\n",
      "        result = _grouped_plot_by_column(plot_group, data, columns=columns,\r\n",
      "                                         by=by, grid=grid, figsize=figsize,\r\n",
      "                                         ax=ax, layout=layout,\r\n",
      "                                         return_type=return_type)\r\n",
      "    else:\r\n",
      "        if return_type is None:\r\n",
      "            return_type = 'axes'\r\n",
      "        if layout is not None:\r\n",
      "            raise ValueError(\"The 'layout' keyword is not supported when \"\r\n",
      "                             \"'by' is None\")\r\n",
      "\r\n",
      "        if ax is None:\r\n",
      "            rc = {'figure.figsize': figsize} if figsize is not None else {}\r\n",
      "            ax = _gca(rc)\r\n",
      "        data = data._get_numeric_data()\r\n",
      "        if columns is None:\r\n",
      "            columns = data.columns\r\n",
      "        else:\r\n",
      "            data = data[columns]\r\n",
      "\r\n",
      "        result = plot_group(columns, data.values.T, ax)\r\n",
      "        ax.grid(grid)\r\n",
      "\r\n",
      "    return result\r\n",
      "\r\n",
      "\r\n",
      "@Appender(_shared_docs['boxplot'] % _shared_doc_kwargs)\r\n",
      "def boxplot_frame(self, column=None, by=None, ax=None, fontsize=None, rot=0,\r\n",
      "                  grid=True, figsize=None, layout=None,\r\n",
      "                  return_type=None, **kwds):\r\n",
      "    import matplotlib.pyplot as plt\r\n",
      "    _converter._WARN = False\r\n",
      "    ax = boxplot(self, column=column, by=by, ax=ax, fontsize=fontsize,\r\n",
      "                 grid=grid, rot=rot, figsize=figsize, layout=layout,\r\n",
      "                 return_type=return_type, **kwds)\r\n",
      "    plt.draw_if_interactive()\r\n",
      "    return ax\r\n",
      "\r\n",
      "\r\n",
      "def scatter_plot(data, x, y, by=None, ax=None, figsize=None, grid=False,\r\n",
      "                 **kwargs):\r\n",
      "    \"\"\"\r\n",
      "    Make a scatter plot from two DataFrame columns\r\n",
      "\r\n",
      "    Parameters\r\n",
      "    ----------\r\n",
      "    data : DataFrame\r\n",
      "    x : Column name for the x-axis values\r\n",
      "    y : Column name for the y-axis values\r\n",
      "    ax : Matplotlib axis object\r\n",
      "    figsize : A tuple (width, height) in inches\r\n",
      "    grid : Setting this to True will show the grid\r\n",
      "    kwargs : other plotting keyword arguments\r\n",
      "        To be passed to scatter function\r\n",
      "\r\n",
      "    Returns\r\n",
      "    -------\r\n",
      "    fig : matplotlib.Figure\r\n",
      "    \"\"\"\r\n",
      "    import matplotlib.pyplot as plt\r\n",
      "\r\n",
      "    kwargs.setdefault('edgecolors', 'none')\r\n",
      "\r\n",
      "    def plot_group(group, ax):\r\n",
      "        xvals = group[x].values\r\n",
      "        yvals = group[y].values\r\n",
      "        ax.scatter(xvals, yvals, **kwargs)\r\n",
      "        ax.grid(grid)\r\n",
      "\r\n",
      "    if by is not None:\r\n",
      "        fig = _grouped_plot(plot_group, data, by=by, figsize=figsize, ax=ax)\r",
      "\r\n",
      "    else:\r\n",
      "        if ax is None:\r\n",
      "            fig = plt.figure()\r\n",
      "            ax = fig.add_subplot(111)\r\n",
      "        else:\r\n",
      "            fig = ax.get_figure()\r\n",
      "        plot_group(data, ax)\r\n",
      "        ax.set_ylabel(pprint_thing(y))\r\n",
      "        ax.set_xlabel(pprint_thing(x))\r\n",
      "\r\n",
      "        ax.grid(grid)\r\n",
      "\r\n",
      "    return fig\r\n",
      "\r\n",
      "\r\n",
      "def hist_frame(data, column=None, by=None, grid=True, xlabelsize=None,\r\n",
      "               xrot=None, ylabelsize=None, yrot=None, ax=None, sharex=False,\r\n",
      "               sharey=False, figsize=None, layout=None, bins=10, **kwds):\r\n",
      "    \"\"\"\r\n",
      "    Draw histogram of the DataFrame's series using matplotlib / pylab.\r\n",
      "\r\n",
      "    Parameters\r\n",
      "    ----------\r\n",
      "    data : DataFrame\r\n",
      "    column : string or sequence\r\n",
      "        If passed, will be used to limit data to a subset of columns\r\n",
      "    by : object, optional\r\n",
      "        If passed, then used to form histograms for separate groups\r\n",
      "    grid : boolean, default True\r\n",
      "        Whether to show axis grid lines\r\n",
      "    xlabelsize : int, default None\r\n",
      "        If specified changes the x-axis label size\r\n",
      "    xrot : float, default None\r\n",
      "        rotation of x axis labels\r\n",
      "    ylabelsize : int, default None\r\n",
      "        If specified changes the y-axis label size\r\n",
      "    yrot : float, default None\r\n",
      "        rotation of y axis labels\r\n",
      "    ax : matplotlib axes object, default None\r\n",
      "    sharex : boolean, default True if ax is None else False\r\n",
      "        In case subplots=True, share x axis and set some x axis labels to\r\n",
      "        invisible; defaults to True if ax is None otherwise False if an ax\r\n",
      "        is passed in; Be aware, that passing in both an ax and sharex=True\r\n",
      "        will alter all x axis labels for all subplots in a figure!\r\n",
      "    sharey : boolean, default False\r\n",
      "        In case subplots=True, share y axis and set some y axis labels to\r\n",
      "        invisible\r\n",
      "    figsize : tuple\r\n",
      "        The size of the figure to create in inches by default\r\n",
      "    layout : tuple, optional\r\n",
      "        Tuple of (rows, columns) for the layout of the histograms\r\n",
      "    bins : integer, default 10\r\n",
      "        Number of histogram bins to be used\r\n",
      "    kwds : other plotting keyword arguments\r\n",
      "        To be passed to hist function\r\n",
      "    \"\"\"\r\n",
      "    _converter._WARN = False\r\n",
      "    if by is not None:\r\n",
      "        axes = grouped_hist(data, column=column, by=by, ax=ax, grid=grid,\r\n",
      "                            figsize=figsize, sharex=sharex, sharey=sharey,\r\n",
      "                            layout=layout, bins=bins, xlabelsize=xlabelsize,\r\n",
      "                            xrot=xrot, ylabelsize=ylabelsize,\r\n",
      "                            yrot=yrot, **kwds)\r\n",
      "        return axes\r\n",
      "\r\n",
      "    if column is not None:\r\n",
      "        if not isinstance(column, (list, np.ndarray, Index)):\r\n",
      "            column = [column]\r\n",
      "        data = data[column]\r\n",
      "    data = data._get_numeric_data()\r\n",
      "    naxes = len(data.columns)\r\n",
      "\r\n",
      "    fig, axes = _subplots(naxes=naxes, ax=ax, squeeze=False,\r\n",
      "                          sharex=sharex, sharey=sharey, figsize=figsize,\r\n",
      "                          layout=layout)\r\n",
      "    _axes = _flatten(axes)\r\n",
      "\r\n",
      "    for i, col in enumerate(_try_sort(data.columns)):\r\n",
      "        ax = _axes[i]\r\n",
      "        ax.hist(data[col].dropna().values, bins=bins, **kwds)\r\n",
      "        ax.set_title(col)\r\n",
      "        ax.grid(grid)\r\n",
      "\r\n",
      "    _set_ticks_props(axes, xlabelsize=xlabelsize, xrot=xrot,\r\n",
      "                     ylabelsize=ylabelsize, yrot=yrot)\r\n",
      "    fig.subplots_adjust(wspace=0.3, hspace=0.3)\r\n",
      "\r\n",
      "    return axes\r\n",
      "\r\n",
      "\r\n",
      "def hist_series(self, by=None, ax=None, grid=True, xlabelsize=None,\r\n",
      "                xrot=None, ylabelsize=None, yrot=None, figsize=None,\r\n",
      "                bins=10, **kwds):\r\n",
      "    \"\"\"\r\n",
      "    Draw histogram of the input series using matplotlib\r\n",
      "\r\n",
      "    Parameters\r\n",
      "    ----------\r\n",
      "    by : object, optional\r\n",
      "        If passed, then used to form histograms for separate groups\r\n",
      "    ax : matplotlib axis object\r\n",
      "        If not passed, uses gca()\r\n",
      "    grid : boolean, default True\r\n",
      "        Whether to show axis grid lines\r\n",
      "    xlabelsize : int, default None\r\n",
      "        If specified changes the x-axis label size\r\n",
      "    xrot : float, default None\r\n",
      "        rotation of x axis labels\r\n",
      "    ylabelsize : int, default None\r\n",
      "        If specified changes the y-axis label size\r\n",
      "    yrot : float, default None\r\n",
      "        rotation of y axis labels\r\n",
      "    figsize : tuple, default None\r\n",
      "        figure size in inches by default\r\n",
      "    bins: integer, default 10\r\n",
      "        Number of histogram bins to be used\r\n",
      "    kwds : keywords\r\n",
      "        To be passed to the actual plotting function\r\n",
      "\r\n",
      "    Notes\r\n",
      "    -----\r\n",
      "    See matplotlib documentation online for more on this\r\n",
      "\r\n",
      "    \"\"\"\r\n",
      "    import matplotlib.pyplot as plt\r\n",
      "\r\n",
      "    if by is None:\r\n",
      "        if kwds.get('layout', None) is not None:\r\n",
      "            raise ValueError(\"The 'layout' keyword is not supported when \"\r\n",
      "                             \"'by' is None\")\r\n",
      "        # hack until the plotting interface is a bit more unified\r\n",
      "        fig = kwds.pop('figure', plt.gcf() if plt.get_fignums() else\r\n",
      "                       plt.figure(figsize=figsize))\r\n",
      "        if (figsize is not None and tuple(figsize) !=\r\n",
      "                tuple(fig.get_size_inches())):\r\n",
      "            fig.set_size_inches(*figsize, forward=True)\r\n",
      "        if ax is None:\r\n",
      "            ax = fig.gca()\r\n",
      "        elif ax.get_figure() != fig:\r\n",
      "            raise AssertionError('passed axis not bound to passed figure')\r\n",
      "        values = self.dropna().values\r\n",
      "\r\n",
      "        ax.hist(values, bins=bins, **kwds)\r\n",
      "        ax.grid(grid)\r\n",
      "        axes = np.array([ax])\r\n",
      "\r\n",
      "        _set_ticks_props(axes, xlabelsize=xlabelsize, xrot=xrot,\r\n",
      "                         ylabelsize=ylabelsize, yrot=yrot)\r\n",
      "\r\n",
      "    else:\r\n",
      "        if 'figure' in kwds:\r\n",
      "            raise ValueError(\"Cannot pass 'figure' when using the \"\r\n",
      "                             \"'by' argument, since a new 'Figure' instance \"\r\n",
      "                             \"will be created\")\r\n",
      "        axes = grouped_hist(self, by=by, ax=ax, grid=grid, figsize=figsize,\r\n",
      "                            bins=bins, xlabelsize=xlabelsize, xrot=xrot,\r\n",
      "                            ylabelsize=ylabelsize, yrot=yrot, **kwds)\r\n",
      "\r\n",
      "    if hasattr(axes, 'ndim'):\r\n",
      "        if axes.ndim == 1 and len(axes) == 1:\r\n",
      "            return axes[0]\r\n",
      "    return axes\r\n",
      "\r\n",
      "\r\n",
      "def grouped_hist(data, column=None, by=None, ax=None, bins=50, figsize=None,\r\n",
      "                 layout=None, sharex=False, sharey=False, rot=90, grid=True,\r\n",
      "                 xlabelsize=None, xrot=None, ylabelsize=None, yrot=None,\r\n",
      "                 **kwargs):\r\n",
      "    \"\"\"\r\n",
      "    Grouped histogram\r\n",
      "\r\n",
      "    Parameters\r\n",
      "    ----------\r\n",
      "    data: Series/DataFrame\r\n",
      "    column: object, optional\r\n",
      "    by: object, optional\r\n",
      "    ax: axes, optional\r\n",
      "    bins: int, default 50\r\n",
      "    figsize: tuple, optional\r\n",
      "    layout: optional\r\n",
      "    sharex: boolean, default False\r\n",
      "    sharey: boolean, default False\r\n",
      "    rot: int, default 90\r\n",
      "    grid: bool, default True\r\n",
      "    kwargs: dict, keyword arguments passed to matplotlib.Axes.hist\r\n",
      "\r\n",
      "    Returns\r\n",
      "    -------\r\n",
      "    axes: collection of Matplotlib Axes\r\n",
      "    \"\"\"\r\n",
      "    _converter._WARN = False\r\n",
      "\r\n",
      "    def plot_group(group, ax):\r\n",
      "        ax.hist(group.dropna().values, bins=bins, **kwargs)\r\n",
      "\r\n",
      "    xrot = xrot or rot\r\n",
      "\r\n",
      "    fig, axes = _grouped_plot(plot_group, data, column=column,\r\n",
      "                              by=by, sharex=sharex, sharey=sharey, ax=ax,\r\n",
      "                              figsize=figsize, layout=layout, rot=rot)\r\n",
      "\r\n",
      "    _set_ticks_props(axes, xlabelsize=xlabelsize, xrot=xrot,\r\n",
      "                     ylabelsize=ylabelsize, yrot=yrot)\r\n",
      "\r\n",
      "    fig.subplots_adjust(bottom=0.15, top=0.9, left=0.1, right=0.9,\r\n",
      "                        hspace=0.5, wspace=0.3)\r\n",
      "    return axes\r\n",
      "\r\n",
      "\r\n",
      "def boxplot_frame_groupby(grouped, subplots=True, column=None, fontsize=None,\r\n",
      "                          rot=0, grid=True, ax=None, figsize=None,\r\n",
      "                          layout=None, **kwds):\r\n",
      "    \"\"\"\r\n",
      "    Make box plots from DataFrameGroupBy data.\r\n",
      "\r\n",
      "    Parameters\r\n",
      "    ----------\r\n",
      "    grouped : Grouped DataFrame\r\n",
      "    subplots :\r\n",
      "        * ``False`` - no subplots will be used\r\n",
      "        * ``True`` - create a subplot for each group\r\n",
      "    column : column name or list of names, or vector\r\n",
      "        Can be any valid input to groupby\r\n",
      "    fontsize : int or string\r\n",
      "    rot : label rotation angle\r\n",
      "    grid : Setting this to True will show the grid\r\n",
      "    ax : Matplotlib axis object, default None\r\n",
      "    figsize : A tuple (width, height) in inches\r\n",
      "    layout : tuple (optional)\r\n",
      "        (rows, columns) for the layout of the plot\r\n",
      "    kwds : other plotting keyword arguments to be passed to matplotlib boxplot\r\n",
      "           function\r\n",
      "\r\n",
      "    Returns\r\n",
      "    -------\r\n",
      "    dict of key/value = group key/DataFrame.boxplot return value\r\n",
      "    or DataFrame.boxplot return value in case subplots=figures=False\r\n",
      "\r\n",
      "    Examples\r\n",
      "    --------\r\n",
      "    >>> import pandas\r\n",
      "    >>> import numpy as np\r\n",
      "    >>> import itertools\r\n",
      "    >>>\r\n",
      "    >>> tuples = [t for t in itertools.product(range(1000), range(4))]\r\n",
      "    >>> index = pandas.MultiIndex.from_tuples(tuples, names=['lvl0', 'lvl1'])\r\n",
      "    >>> data = np.random.randn(len(index),4)\r\n",
      "    >>> df = pandas.DataFrame(data, columns=list('ABCD'), index=index)\r\n",
      "    >>>\r\n",
      "    >>> grouped = df.groupby(level='lvl1')\r\n",
      "    >>> boxplot_frame_groupby(grouped)\r\n",
      "    >>>\r\n",
      "    >>> grouped = df.unstack(level='lvl1').groupby(level=0, axis=1)\r\n",
      "    >>> boxplot_frame_groupby(grouped, subplots=False)\r\n",
      "    \"\"\"\r\n",
      "    _converter._WARN = False\r\n",
      "    if subplots is True:\r\n",
      "        naxes = len(grouped)\r\n",
      "        fig, axes = _subplots(naxes=naxes, squeeze=False,\r\n",
      "                              ax=ax, sharex=False, sharey=True,\r\n",
      "                              figsize=figsize, layout=layout)\r\n",
      "        axes = _flatten(axes)\r\n",
      "\r\n",
      "        from pandas.core.series import Series\r\n",
      "        ret = Series()\r\n",
      "        for (key, group), ax in zip(grouped, axes):\r\n",
      "            d = group.boxplot(ax=ax, column=column, fontsize=fontsize,\r\n",
      "                              rot=rot, grid=grid, **kwds)\r\n",
      "            ax.set_title(pprint_thing(key))\r\n",
      "            ret.loc[key] = d\r\n",
      "        fig.subplots_adjust(bottom=0.15, top=0.9, left=0.1,\r\n",
      "                            right=0.9, wspace=0.2)\r\n",
      "    else:\r\n",
      "        from pandas.core.reshape.concat import concat\r\n",
      "        keys, frames = zip(*grouped)\r\n",
      "        if grouped.axis == 0:\r\n",
      "            df = concat(frames, keys=keys, axis=1)\r\n",
      "        else:\r\n",
      "            if len(frames) > 1:\r\n",
      "                df = frames[0].join(frames[1::])\r\n",
      "            else:\r\n",
      "                df = frames[0]\r\n",
      "        ret = df.boxplot(column=column, fontsize=fontsize, rot=rot,\r\n",
      "                         grid=grid, ax=ax, figsize=figsize,\r\n",
      "                         layout=layout, **kwds)\r\n",
      "    return ret\r\n",
      "\r\n",
      "\r\n",
      "def _grouped_plot(plotf, data, column=None, by=None, numeric_only=True,\r\n",
      "                  figsize=None, sharex=True, sharey=True, layout=None,\r\n",
      "                  rot=0, ax=None, **kwargs):\r\n",
      "    from pandas import DataFrame\r\n",
      "\r\n",
      "    if figsize == 'default':\r\n",
      "        # allowed to specify mpl default with 'default'\r\n",
      "        warnings.warn(\"figsize='default' is deprecated. Specify figure\"\r\n",
      "                      \"size by tuple instead\", FutureWarning, stacklevel=4)\r\n",
      "        figsize = None\r\n",
      "\r\n",
      "    grouped = data.groupby(by)\r\n",
      "    if column is not None:\r\n",
      "        grouped = grouped[column]\r\n",
      "\r\n",
      "    naxes = len(grouped)\r\n",
      "    fig, axes = _subplots(naxes=naxes, figsize=figsize,\r\n",
      "                          sharex=sharex, sharey=sharey, ax=ax,\r",
      "\r\n",
      "                          layout=layout)\r\n",
      "\r\n",
      "    _axes = _flatten(axes)\r\n",
      "\r\n",
      "    for i, (key, group) in enumerate(grouped):\r\n",
      "        ax = _axes[i]\r\n",
      "        if numeric_only and isinstance(group, DataFrame):\r\n",
      "            group = group._get_numeric_data()\r\n",
      "        plotf(group, ax, **kwargs)\r\n",
      "        ax.set_title(pprint_thing(key))\r\n",
      "\r\n",
      "    return fig, axes\r\n",
      "\r\n",
      "\r\n",
      "def _grouped_plot_by_column(plotf, data, columns=None, by=None,\r\n",
      "                            numeric_only=True, grid=False,\r\n",
      "                            figsize=None, ax=None, layout=None,\r\n",
      "                            return_type=None, **kwargs):\r\n",
      "    grouped = data.groupby(by)\r\n",
      "    if columns is None:\r\n",
      "        if not isinstance(by, (list, tuple)):\r\n",
      "            by = [by]\r\n",
      "        columns = data._get_numeric_data().columns.difference(by)\r\n",
      "    naxes = len(columns)\r\n",
      "    fig, axes = _subplots(naxes=naxes, sharex=True, sharey=True,\r\n",
      "                          figsize=figsize, ax=ax, layout=layout)\r\n",
      "\r\n",
      "    _axes = _flatten(axes)\r\n",
      "\r\n",
      "    ax_values = []\r\n",
      "\r\n",
      "    for i, col in enumerate(columns):\r\n",
      "        ax = _axes[i]\r\n",
      "        gp_col = grouped[col]\r\n",
      "        keys, values = zip(*gp_col)\r\n",
      "        re_plotf = plotf(keys, values, ax, **kwargs)\r\n",
      "        ax.set_title(col)\r\n",
      "        ax.set_xlabel(pprint_thing(by))\r\n",
      "        ax_values.append(re_plotf)\r\n",
      "        ax.grid(grid)\r\n",
      "\r\n",
      "    from pandas.core.series import Series\r\n",
      "    result = Series(ax_values, index=columns)\r\n",
      "\r\n",
      "    # Return axes in multiplot case, maybe revisit later # 985\r\n",
      "    if return_type is None:\r\n",
      "        result = axes\r\n",
      "\r\n",
      "    byline = by[0] if len(by) == 1 else by\r\n",
      "    fig.suptitle('Boxplot grouped by %s' % byline)\r\n",
      "    fig.subplots_adjust(bottom=0.15, top=0.9, left=0.1, right=0.9, wspace=0.2)\r\n",
      "\r\n",
      "    return result\r\n",
      "\r\n",
      "\r\n",
      "class BasePlotMethods(PandasObject):\r\n",
      "\r\n",
      "    def __init__(self, data):\r\n",
      "        self._data = data\r\n",
      "\r\n",
      "    def __call__(self, *args, **kwargs):\r\n",
      "        raise NotImplementedError\r\n",
      "\r\n",
      "\r\n",
      "class SeriesPlotMethods(BasePlotMethods):\r\n",
      "    \"\"\"Series plotting accessor and method\r\n",
      "\r\n",
      "    Examples\r\n",
      "    --------\r\n",
      "    >>> s.plot.line()\r\n",
      "    >>> s.plot.bar()\r\n",
      "    >>> s.plot.hist()\r\n",
      "\r\n",
      "    Plotting methods can also be accessed by calling the accessor as a method\r\n",
      "    with the ``kind`` argument:\r\n",
      "    ``s.plot(kind='line')`` is equivalent to ``s.plot.line()``\r\n",
      "    \"\"\"\r\n",
      "\r\n",
      "    def __call__(self, kind='line', ax=None,\r\n",
      "                 figsize=None, use_index=True, title=None, grid=None,\r\n",
      "                 legend=False, style=None, logx=False, logy=False,\r\n",
      "                 loglog=False, xticks=None, yticks=None,\r\n",
      "                 xlim=None, ylim=None,\r\n",
      "                 rot=None, fontsize=None, colormap=None, table=False,\r\n",
      "                 yerr=None, xerr=None,\r\n",
      "                 label=None, secondary_y=False, **kwds):\r\n",
      "        return plot_series(self._data, kind=kind, ax=ax, figsize=figsize,\r\n",
      "                           use_index=use_index, title=title, grid=grid,\r\n",
      "                           legend=legend, style=style, logx=logx, logy=logy,\r\n",
      "                           loglog=loglog, xticks=xticks, yticks=yticks,\r\n",
      "                           xlim=xlim, ylim=ylim, rot=rot, fontsize=fontsize,\r\n",
      "                           colormap=colormap, table=table, yerr=yerr,\r\n",
      "                           xerr=xerr, label=label, secondary_y=secondary_y,\r\n",
      "                           **kwds)\r\n",
      "    __call__.__doc__ = plot_series.__doc__\r\n",
      "\r\n",
      "    def line(self, **kwds):\r\n",
      "        \"\"\"\r\n",
      "        Line plot\r\n",
      "\r\n",
      "        .. versionadded:: 0.17.0\r\n",
      "\r\n",
      "        Parameters\r\n",
      "        ----------\r\n",
      "        **kwds : optional\r\n",
      "            Keyword arguments to pass on to :py:meth:`pandas.Series.plot`.\r\n",
      "\r\n",
      "        Returns\r\n",
      "        -------\r\n",
      "        axes : matplotlib.AxesSubplot or np.array of them\r\n",
      "        \"\"\"\r\n",
      "        return self(kind='line', **kwds)\r\n",
      "\r\n",
      "    def bar(self, **kwds):\r\n",
      "        \"\"\"\r\n",
      "        Vertical bar plot\r\n",
      "\r\n",
      "        .. versionadded:: 0.17.0\r\n",
      "\r\n",
      "        Parameters\r\n",
      "        ----------\r\n",
      "        **kwds : optional\r\n",
      "            Keyword arguments to pass on to :py:meth:`pandas.Series.plot`.\r\n",
      "\r\n",
      "        Returns\r\n",
      "        -------\r\n",
      "        axes : matplotlib.AxesSubplot or np.array of them\r\n",
      "        \"\"\"\r\n",
      "        return self(kind='bar', **kwds)\r\n",
      "\r\n",
      "    def barh(self, **kwds):\r\n",
      "        \"\"\"\r\n",
      "        Horizontal bar plot\r\n",
      "\r\n",
      "        .. versionadded:: 0.17.0\r\n",
      "\r\n",
      "        Parameters\r\n",
      "        ----------\r\n",
      "        **kwds : optional\r\n",
      "            Keyword arguments to pass on to :py:meth:`pandas.Series.plot`.\r\n",
      "\r\n",
      "        Returns\r\n",
      "        -------\r\n",
      "        axes : matplotlib.AxesSubplot or np.array of them\r\n",
      "        \"\"\"\r\n",
      "        return self(kind='barh', **kwds)\r\n",
      "\r\n",
      "    def box(self, **kwds):\r\n",
      "        \"\"\"\r\n",
      "        Boxplot\r\n",
      "\r\n",
      "        .. versionadded:: 0.17.0\r\n",
      "\r\n",
      "        Parameters\r\n",
      "        ----------\r\n",
      "        **kwds : optional\r\n",
      "            Keyword arguments to pass on to :py:meth:`pandas.Series.plot`.\r\n",
      "\r\n",
      "        Returns\r\n",
      "        -------\r\n",
      "        axes : matplotlib.AxesSubplot or np.array of them\r\n",
      "        \"\"\"\r\n",
      "        return self(kind='box', **kwds)\r\n",
      "\r\n",
      "    def hist(self, bins=10, **kwds):\r\n",
      "        \"\"\"\r\n",
      "        Histogram\r\n",
      "\r\n",
      "        .. versionadded:: 0.17.0\r\n",
      "\r\n",
      "        Parameters\r\n",
      "        ----------\r\n",
      "        bins: integer, default 10\r",
      "\r\n",
      "            Number of histogram bins to be used\r\n",
      "        **kwds : optional\r\n",
      "            Keyword arguments to pass on to :py:meth:`pandas.Series.plot`.\r\n",
      "\r\n",
      "        Returns\r\n",
      "        -------\r\n",
      "        axes : matplotlib.AxesSubplot or np.array of them\r\n",
      "        \"\"\"\r\n",
      "        return self(kind='hist', bins=bins, **kwds)\r\n",
      "\r\n",
      "    def kde(self, **kwds):\r\n",
      "        \"\"\"\r\n",
      "        Kernel Density Estimate plot\r\n",
      "\r\n",
      "        .. versionadded:: 0.17.0\r\n",
      "\r\n",
      "        Parameters\r\n",
      "        ----------\r\n",
      "        **kwds : optional\r\n",
      "            Keyword arguments to pass on to :py:meth:`pandas.Series.plot`.\r\n",
      "\r\n",
      "        Returns\r\n",
      "        -------\r\n",
      "        axes : matplotlib.AxesSubplot or np.array of them\r\n",
      "        \"\"\"\r\n",
      "        return self(kind='kde', **kwds)\r\n",
      "\r\n",
      "    density = kde\r\n",
      "\r\n",
      "    def area(self, **kwds):\r\n",
      "        \"\"\"\r\n",
      "        Area plot\r\n",
      "\r\n",
      "        .. versionadded:: 0.17.0\r\n",
      "\r\n",
      "        Parameters\r\n",
      "        ----------\r\n",
      "        **kwds : optional\r\n",
      "            Keyword arguments to pass on to :py:meth:`pandas.Series.plot`.\r\n",
      "\r\n",
      "        Returns\r\n",
      "        -------\r\n",
      "        axes : matplotlib.AxesSubplot or np.array of them\r\n",
      "        \"\"\"\r\n",
      "        return self(kind='area', **kwds)\r\n",
      "\r\n",
      "    def pie(self, **kwds):\r\n",
      "        \"\"\"\r\n",
      "        Pie chart\r\n",
      "\r\n",
      "        .. versionadded:: 0.17.0\r\n",
      "\r\n",
      "        Parameters\r\n",
      "        ----------\r\n",
      "        **kwds : optional\r\n",
      "            Keyword arguments to pass on to :py:meth:`pandas.Series.plot`.\r\n",
      "\r\n",
      "        Returns\r\n",
      "        -------\r\n",
      "        axes : matplotlib.AxesSubplot or np.array of them\r\n",
      "        \"\"\"\r\n",
      "        return self(kind='pie', **kwds)\r\n",
      "\r\n",
      "\r\n",
      "class FramePlotMethods(BasePlotMethods):\r\n",
      "    \"\"\"DataFrame plotting accessor and method\r\n",
      "\r\n",
      "    Examples\r\n",
      "    --------\r\n",
      "    >>> df.plot.line()\r\n",
      "    >>> df.plot.scatter('x', 'y')\r\n",
      "    >>> df.plot.hexbin()\r\n",
      "\r\n",
      "    These plotting methods can also be accessed by calling the accessor as a\r\n",
      "    method with the ``kind`` argument:\r\n",
      "    ``df.plot(kind='line')`` is equivalent to ``df.plot.line()``\r\n",
      "    \"\"\"\r\n",
      "\r\n",
      "    def __call__(self, x=None, y=None, kind='line', ax=None,\r\n",
      "                 subplots=False, sharex=None, sharey=False, layout=None,\r\n",
      "                 figsize=None, use_index=True, title=None, grid=None,\r\n",
      "                 legend=True, style=None, logx=False, logy=False, loglog=False,\r\n",
      "                 xticks=None, yticks=None, xlim=None, ylim=None,\r\n",
      "                 rot=None, fontsize=None, colormap=None, table=False,\r\n",
      "                 yerr=None, xerr=None,\r\n",
      "                 secondary_y=False, sort_columns=False, **kwds):\r\n",
      "        return plot_frame(self._data, kind=kind, x=x, y=y, ax=ax,\r\n",
      "                          subplots=subplots, sharex=sharex, sharey=sharey,\r\n",
      "                          layout=layout, figsize=figsize, use_index=use_index,\r\n",
      "                          title=title, grid=grid, legend=legend, style=style,\r\n",
      "                          logx=logx, logy=logy, loglog=loglog, xticks=xticks,\r\n",
      "                          yticks=yticks, xlim=xlim, ylim=ylim, rot=rot,\r\n",
      "                          fontsize=fontsize, colormap=colormap, table=table,\r\n",
      "                          yerr=yerr, xerr=xerr, secondary_y=secondary_y,\r\n",
      "                          sort_columns=sort_columns, **kwds)\r\n",
      "    __call__.__doc__ = plot_frame.__doc__\r\n",
      "\r\n",
      "    def line(self, x=None, y=None, **kwds):\r\n",
      "        \"\"\"\r\n",
      "        Line plot\r\n",
      "\r\n",
      "        .. versionadded:: 0.17.0\r\n",
      "\r\n",
      "        Parameters\r\n",
      "        ----------\r\n",
      "        x, y : label or position, optional\r\n",
      "            Coordinates for each point.\r\n",
      "        **kwds : optional\r\n",
      "            Keyword arguments to pass on to :py:meth:`pandas.DataFrame.plot`.\r\n",
      "\r\n",
      "        Returns\r\n",
      "        -------\r\n",
      "        axes : matplotlib.AxesSubplot or np.array of them\r\n",
      "        \"\"\"\r\n",
      "        return self(kind='line', x=x, y=y, **kwds)\r\n",
      "\r\n",
      "    def bar(self, x=None, y=None, **kwds):\r\n",
      "        \"\"\"\r\n",
      "        Vertical bar plot\r\n",
      "\r\n",
      "        .. versionadded:: 0.17.0\r\n",
      "\r\n",
      "        Parameters\r\n",
      "        ----------\r\n",
      "        x, y : label or position, optional\r\n",
      "            Coordinates for each point.\r\n",
      "        **kwds : optional\r\n",
      "            Keyword arguments to pass on to :py:meth:`pandas.DataFrame.plot`.\r\n",
      "\r\n",
      "        Returns\r\n",
      "        -------\r\n",
      "        axes : matplotlib.AxesSubplot or np.array of them\r\n",
      "        \"\"\"\r\n",
      "        return self(kind='bar', x=x, y=y, **kwds)\r\n",
      "\r\n",
      "    def barh(self, x=None, y=None, **kwds):\r\n",
      "        \"\"\"\r\n",
      "        Horizontal bar plot\r\n",
      "\r\n",
      "        .. versionadded:: 0.17.0\r\n",
      "\r\n",
      "        Parameters\r\n",
      "        ----------\r\n",
      "        x, y : label or position, optional\r\n",
      "            Coordinates for each point.\r\n",
      "        **kwds : optional\r\n",
      "            Keyword arguments to pass on to :py:meth:`pandas.DataFrame.plot`.\r\n",
      "\r\n",
      "        Returns\r\n",
      "        -------\r\n",
      "        axes : matplotlib.AxesSubplot or np.array of them\r\n",
      "        \"\"\"\r\n",
      "        return self(kind='barh', x=x, y=y, **kwds)\r\n",
      "\r\n",
      "    def box(self, by=None, **kwds):\r\n",
      "        r\"\"\"\r\n",
      "        Boxplot\r\n",
      "\r\n",
      "        .. versionadded:: 0.17.0\r\n",
      "\r\n",
      "        Parameters\r\n",
      "        ----------\r\n",
      "        by : string or sequence\r\n",
      "            Column in the DataFrame to group by.\r\n",
      "        \\*\\*kwds : optional\r\n",
      "            Keyword arguments to pass on to :py:meth:`pandas.DataFrame.plot`.\r\n",
      "\r\n",
      "        Returns\r\n",
      "        -------\r\n",
      "        axes : matplotlib.AxesSubplot or np.array of them\r\n",
      "        \"\"\"\r\n",
      "        return self(kind='box', by=by, **kwds)\r\n",
      "\r\n",
      "    def hist(self, by=None, bins=10, **kwds):\r\n",
      "        \"\"\"\r\n",
      "        Histogram\r\n",
      "\r\n",
      "        .. versionadded:: 0.17.0\r\n",
      "\r\n",
      "        Parameters\r\n",
      "        ----------\r\n",
      "        by : string or sequence\r\n",
      "            Column in the DataFrame to group by.\r\n",
      "        bins: integer, default 10\r\n",
      "            Number of histogram bins to be used\r\n",
      "        **kwds : optional\r\n",
      "            Keyword arguments to pass on to :py:meth:`pandas.DataFrame.plot`.\r\n",
      "\r\n",
      "        Returns\r\n",
      "        -------\r\n",
      "        axes : matplotlib.AxesSubplot or np.array of them\r\n",
      "        \"\"\"\r\n",
      "        return self(kind='hist', by=by, bins=bins, **kwds)\r\n",
      "\r\n",
      "    def kde(self, **kwds):\r\n",
      "        \"\"\"\r\n",
      "        Kernel Density Estimate plot\r\n",
      "\r\n",
      "        .. versionadded:: 0.17.0\r\n",
      "\r\n",
      "        Parameters\r\n",
      "        ----------\r\n",
      "        **kwds : optional\r\n",
      "            Keyword arguments to pass on to :py:meth:`pandas.DataFrame.plot`.\r\n",
      "\r\n",
      "        Returns\r\n",
      "        -------\r\n",
      "        axes : matplotlib.AxesSubplot or np.array of them\r\n",
      "        \"\"\"\r\n",
      "        return self(kind='kde', **kwds)\r\n",
      "\r\n",
      "    density = kde\r\n",
      "\r\n",
      "    def area(self, x=None, y=None, **kwds):\r\n",
      "        \"\"\"\r\n",
      "        Area plot\r\n",
      "\r\n",
      "        .. versionadded:: 0.17.0\r\n",
      "\r\n",
      "        Parameters\r\n",
      "        ----------\r\n",
      "        x, y : label or position, optional\r\n",
      "            Coordinates for each point.\r\n",
      "        **kwds : optional\r\n",
      "            Keyword arguments to pass on to :py:meth:`pandas.DataFrame.plot`.\r\n",
      "\r\n",
      "        Returns\r\n",
      "        -------\r\n",
      "        axes : matplotlib.AxesSubplot or np.array of them\r\n",
      "        \"\"\"\r\n",
      "        return self(kind='area', x=x, y=y, **kwds)\r\n",
      "\r\n",
      "    def pie(self, y=None, **kwds):\r\n",
      "        \"\"\"\r\n",
      "        Pie chart\r\n",
      "\r\n",
      "        .. versionadded:: 0.17.0\r\n",
      "\r\n",
      "        Parameters\r\n",
      "        ----------\r\n",
      "        y : label or position, optional\r\n",
      "            Column to plot.\r\n",
      "        **kwds : optional\r\n",
      "            Keyword arguments to pass on to :py:meth:`pandas.DataFrame.plot`.\r\n",
      "\r\n",
      "        Returns\r\n",
      "        -------\r\n",
      "        axes : matplotlib.AxesSubplot or np.array of them\r\n",
      "        \"\"\"\r\n",
      "        return self(kind='pie', y=y, **kwds)\r\n",
      "\r\n",
      "    def scatter(self, x, y, s=None, c=None, **kwds):\r\n",
      "        \"\"\"\r\n",
      "        Scatter plot\r\n",
      "\r\n",
      "        .. versionadded:: 0.17.0\r\n",
      "\r\n",
      "        Parameters\r\n",
      "        ----------\r\n",
      "        x, y : label or position, optional\r\n",
      "            Coordinates for each point.\r\n",
      "        s : scalar or array_like, optional\r\n",
      "            Size of each point.\r\n",
      "        c : label or position, optional\r\n",
      "            Color of each point.\r\n",
      "        **kwds : optional\r\n",
      "            Keyword arguments to pass on to :py:meth:`pandas.DataFrame.plot`.\r\n",
      "\r\n",
      "        Returns\r\n",
      "        -------\r\n",
      "        axes : matplotlib.AxesSubplot or np.array of them\r\n",
      "        \"\"\"\r\n",
      "        return self(kind='scatter', x=x, y=y, c=c, s=s, **kwds)\r\n",
      "\r\n",
      "    def hexbin(self, x, y, C=None, reduce_C_function=None, gridsize=None,\r\n",
      "               **kwds):\r\n",
      "        \"\"\"\r\n",
      "        Hexbin plot\r\n",
      "\r\n",
      "        .. versionadded:: 0.17.0\r\n",
      "\r\n",
      "        Parameters\r\n",
      "        ----------\r\n",
      "        x, y : label or position, optional\r\n",
      "            Coordinates for each point.\r\n",
      "        C : label or position, optional\r\n",
      "            The value at each `(x, y)` point.\r\n",
      "        reduce_C_function : callable, optional\r\n",
      "            Function of one argument that reduces all the values in a bin to\r\n",
      "            a single number (e.g. `mean`, `max`, `sum`, `std`).\r\n",
      "        gridsize : int, optional\r\n",
      "            Number of bins.\r\n",
      "        **kwds : optional\r\n",
      "            Keyword arguments to pass on to :py:meth:`pandas.DataFrame.plot`.\r\n",
      "\r\n",
      "        Returns\r\n",
      "        -------\r\n",
      "        axes : matplotlib.AxesSubplot or np.array of them\r\n",
      "        \"\"\"\r\n",
      "        if reduce_C_function is not None:\r\n",
      "            kwds['reduce_C_function'] = reduce_C_function\r\n",
      "        if gridsize is not None:\r\n",
      "            kwds['gridsize'] = gridsize\r\n",
      "        return self(kind='hexbin', x=x, y=y, C=C, **kwds)\r\n"
     ]
    }
   ],
   "source": [
    "import inspect\n",
    "temp_df.plot.barh\n",
    "\n",
    "!cat ~/anaconda3/lib/python3.6/site-packages/pandas/plotting/_core.py"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th>age</th>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>gender</th>\n",
       "      <th>age</th>\n",
       "      <th></th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th rowspan=\"4\" valign=\"top\">F</th>\n",
       "      <th>30-34</th>\n",
       "      <td>11</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>45-49</th>\n",
       "      <td>4</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>35-39</th>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>40-44</th>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th rowspan=\"4\" valign=\"top\">M</th>\n",
       "      <th>30-34</th>\n",
       "      <td>18</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>35-39</th>\n",
       "      <td>9</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>40-44</th>\n",
       "      <td>5</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>45-49</th>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "              age\n",
       "gender age       \n",
       "F      30-34   11\n",
       "       45-49    4\n",
       "       35-39    3\n",
       "       40-44    1\n",
       "M      30-34   18\n",
       "       35-39    9\n",
       "       40-44    5\n",
       "       45-49    3"
      ]
     },
     "execution_count": 41,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "fig, ax = plt.subplots(figsize = (15, 10))\n",
    "\n",
    "a"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "30-34    18\n",
       "35-39     9\n",
       "40-44     5\n",
       "45-49     3\n",
       "Name: age, dtype: int64"
      ]
     },
     "execution_count": 30,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df_1[df_1.gender == 'M'].age.value_counts()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "30-34    11\n",
       "45-49     4\n",
       "35-39     3\n",
       "40-44     1\n",
       "Name: age, dtype: int64"
      ]
     },
     "execution_count": 32,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df_1[df_1.gender == 'F'].age.value_counts()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Click-through-Rate (CTR)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "useful even though wiki: https://en.wikipedia.org/wiki/Click-through_rate"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<b>Click-through rate (CTR)</b> is the ratio of users who click on a specific link to the number of total users who view a page, email, or advertisement. It is commonly used to measure the success of an online advertising campaign for a particular website as well as the effectiveness of email campaigns. The purpose of click-through rates is to measure the ratio of clicks to impressions of an online ad or email marketing campaign. Generally the higher the CTR the more effective the marketing campaign has been at bringing people to a website"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "uniqueCampaigns = df.xyz_campaign_id.unique()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [],
   "source": [
    "df_1 = df[df.xyz_campaign_id == uniqueCampaigns[0] ]\n",
    "df_2 = df[df.xyz_campaign_id == uniqueCampaigns[1] ]\n",
    "df_3 = df[df.xyz_campaign_id == uniqueCampaigns[2] ]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0.00023399078531863125\n",
      "0.00024408887246319506\n",
      "0.00017609288955581687\n"
     ]
    }
   ],
   "source": [
    "print(df_1['Clicks'].sum() / (df_1['Impressions'].sum() * 1.0) )\n",
    "print(df_2['Clicks'].sum() / (df_2['Impressions'].sum() * 1.0) )\n",
    "print(df_3['Clicks'].sum() / (df_3['Impressions'].sum() * 1.0) )"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "PCA is effected by scale so you need to scale the features in your data before applying PCA. Use StandardScaler to help you standardize the dataset’s features onto unit scale (mean = 0 and variance = 1) which is a requirement for the optimal performance of many machine learning algorithms. If you want to see the negative effect not scaling your data can have, scikit-learn has a section on the effects of not standardizing your data."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Create Additional Features"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "1.) <b>Click-through-rate (CTR)</b>. This is the percentage of how many of our impressions became clicks. A high CTR is often seen as a sign of good creative being presented to a relevant audience. A low click through rate is suggestive of less-than-engaging adverts (design and / or messaging) and / or presentation of adverts to an inappropriate audience. What is seen as a good CTR will depend on the type of advert (website banner, Google Shopping ad, search network test ad etc.) and can vary across sectors, but 2% would be a reasonable benchmark."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "2.) <b>Conversion Rate (CR).</b> This is the percentage of clicks that result in a 'conversion'. What a conversion is will be determined by the objectives of the campaign. It could be a sale, someone completing a contact form on a landing page, downloading an e-book, watching a video, or simply spending more than a particular amount of time or viewing over a target number of pages on a website."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "3.) <b>Cost Per Click (CPC).</b> Self-explanatory this one: how much (on average) did each click cost. While it can often be seen as desirable to reduce the cost per click, the CPC needs to be considered along with other variables. For example, a campaign with an average CPC of £0.5 and a CR of 5% is likely achieving more with its budget than one with a CPC of £0.2 and a CR of 1% (assuming the conversion value is the same."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "4.) <b>Cost Per Conversion.</b> Another simple metric, this figure is often more relevant than the CPC, as it combines the CPC and CR metrics, giving us an easy way to quickly get a feel for campaign effectiveness."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "There are other values that are also very useful in assessing the performance of a marketing campaign. One of these is the <b>conversion value</b>: how much each conversion is worth. For example, our conversion could be a signup form on a landing page to receive information about a new car. If we know that, on average, 1% of people end up purchasing a car for £10,000, we can use that figure in calculating what our target cost per conversion should be."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "For an e-commerce site, we could implement conversion tracking to tie-up the value of specific transactions to particular campaigns, this would allow us to assign the actual amount of revenue generated by each campaign / ad creative."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Knowing the conversion value would allow us to calculate other KPIs such as the <b>Return on Advertising Spend (ROAS)</b>. While advertising campaigns have other benefits (such as increased brand awareness and future purchases based on customer lifetime value) that may factor into the over return on investment (ROI), ROAS can quickly tell us how a campaign is paying for itself. It is simply the revenue as a percentage of the advertising spend. If a campaign costs £100 and leads to £400 sales, the ROAS is 400% (or 4)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "## convert to Python Code. \n",
    "#dataTf <- dataTf %>%\n",
    "#  mutate(CTR = ((Clicks / impr) * 100), CPC = Spent / Clicks)\n",
    "\n",
    "# This is click through rate and cost per click. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### The importance of understanding the client\n",
    "\n",
    "Of course, using ROAS requires an understanding of the client's business. For some clients, a ROAS of 400% might be a great number, for others, they might not be covering their costs. This is why it is important to understand the margins of products being sold through these campaigns.\n",
    "\n",
    "If an advertiser is selling a product for £120 (£100 in the UK after taking off the sales tax) that costs them £40, they are making £60 gross profit and a margin of 60%. If their ROAS is 400% (if calculated using the inc. tax figure), the advertising costs associated with that sale are £30, so there is a net profit of £30.\n",
    "\n",
    "If, on the other hand, the product cost £80 (20% margin), the gross profit is only £20, therefore there is a net loss of £10 (before other business overheads are considered).\n",
    "\n",
    "These simple examples show why it is important to understand, not only the strategic objectives of the marketing activities, but also how specific campaigns support these objectives and how their effectiveness is to be measured and, in the case of retail, what type of margins the client is working with across its product mix."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Obviously the more you spent the more clicks you Get"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "As we might expect, we've got some strong correlations between the amount we spent and how many impressions and clicks we got, with less strong correlations between our spend, clicks and impressions and our conversions. If we wanted to at this point, we could follow this up and calculate the significance of these correlations, but, for now, let's dive into a specific campaign and get a bit more granular."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "From our broad overview of the data, we can see that the more we spend, the more clicks and conversions we seem to get. That's quite reassuring to know, but doesn't really give us the 'actionable insight' we were looking for.\n",
    "\n",
    "For our next stage in the analysis, we'll look at a specific campaign in more detail and see what we can pull out of it. First of all, let's choose a campaign, the one on which we regularly spend the most money and regularly get the most conversions (and for which we have the most data!) might be a good place to start."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Look at Missing Data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Conclusion"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Hopefully this notebook has been of some use to if you're new to pay-per-click advertising, or if you've been looking for new ways to try and improve ROI from your digital campaigns.\n",
    "\n",
    "This notebook is just a quick glimpse into the sort of analyses you can do with your digital advertising datasets, but it really is only a starting point: the correct types of analysis and measures of success will be driven by your own business model and your underlying marketing objectives.\n",
    "\n",
    "For example, if you have a physical business as well as an online presence, how do you factor in people becoming aware of your business, product or promotion online, but converting in store in person? What about products with long buying cycles, where the resulting conversion could be months after the initial\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Google Analytics"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "As briefly discussed above, while ROAS reports on campaigns tactically, ROI is more strategic. To start to work out ROI, we would likely want to start working with data from other sources, such as our website analytics data. As our Facebook ad campaigns can contain plenty information in the URL that sends visitors to our website, we can look at how much website traffic the campaigns generated and how visitors from that campaign interacted with our website."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "With that information, we could look to see if there are other events that we could consider a conversion. Did the visitor subscribe to our email newsletter? Did they spend more than three minutes on the site and browse more than ten pages? Did they bookmark the site and return to make a purchase some time later? If that is the case, their conversion may not be assigned to that campaign in one location, but may be visible as an 'assisted conversion' in the Multi-Channel Funnels section of Google Analytics. Then there are other potential values, such as the ability to now 'remarket/retarget' adverts to that visitor."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Know where your visitors go, how they interact with you and what goals are worth"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Additionally, ROI calculations can consider things such as the lifetime value of the customer. With an advertising campaign, you might not get a sale today, but you might get a visit. Will they come back and purchase later? If a customer makes one purchase, do they end up making more over the next few weeks, months, years...? How much do they spend and does that fall off over time? All of these factors can add up to make that initial cost-per-click better value than it might have seemed at the time."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "By assigning values to the various goals you have in place on your website, and by knowing where visitors came from and how they interact with you over time, you can make better judgments and decisions on how your marketing campaigns are performing."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "With a clear set of objectives, and a good understanding of the business model, you can really delve into the data with specific questions in mind, allowing you to get the answers you need to make appropriate decisions"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python [conda root]",
   "language": "python",
   "name": "conda-root-py"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
